2016-07-28 18:13:49 +01:00
|
|
|
// /***************************************************************************
|
|
|
|
|
// The Disc Image Chef
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : DateHandlers.cs
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
//
|
|
|
|
|
// Component : Helpers.
|
|
|
|
|
//
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Convert several timestamp formats to C# DateTime.
|
|
|
|
|
//
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// This library is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This library is distributed in the hope that it will be useful, but
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2017-12-19 03:50:57 +00:00
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
2016-07-28 18:13:49 +01:00
|
|
|
// ****************************************************************************/
|
2014-04-17 19:58:14 +00:00
|
|
|
|
2012-08-03 01:45:38 +00:00
|
|
|
using System;
|
2017-06-06 21:23:20 +01:00
|
|
|
using System.Text;
|
2017-12-19 19:33:46 +00:00
|
|
|
using DiscImageChef.Console;
|
2012-08-03 01:45:38 +00:00
|
|
|
|
2014-06-15 23:39:34 +01:00
|
|
|
namespace DiscImageChef
|
2012-08-03 01:45:38 +00:00
|
|
|
{
|
2014-04-14 02:29:13 +00:00
|
|
|
public static class DateHandlers
|
|
|
|
|
{
|
2014-04-17 17:13:44 +00:00
|
|
|
static readonly DateTime LisaEpoch = new DateTime(1901, 1, 1, 0, 0, 0);
|
2014-04-14 02:29:13 +00:00
|
|
|
static readonly DateTime MacEpoch = new DateTime(1904, 1, 1, 0, 0, 0);
|
|
|
|
|
static readonly DateTime UNIXEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
|
|
|
|
// Day 0 of Julian Date system
|
2014-04-17 03:45:02 +00:00
|
|
|
static readonly DateTime JulianEpoch = new DateTime(1858, 11, 17, 0, 0, 0);
|
2015-04-20 06:26:33 +01:00
|
|
|
static readonly DateTime AmigaEpoch = new DateTime(1978, 1, 1, 0, 0, 0);
|
2016-09-05 21:22:04 +01:00
|
|
|
static readonly DateTime AppleDoubleEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
2014-04-17 03:45:02 +00:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
public static DateTime MacToDateTime(ulong MacTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return MacEpoch.AddTicks((long)(MacTimeStamp * 10000000));
|
|
|
|
|
}
|
2012-08-03 01:45:38 +00:00
|
|
|
|
2016-07-28 22:25:26 +01:00
|
|
|
public static DateTime LisaToDateTime(uint LisaTimeStamp)
|
2014-04-17 03:45:02 +00:00
|
|
|
{
|
|
|
|
|
return LisaEpoch.AddSeconds(LisaTimeStamp);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 22:25:26 +01:00
|
|
|
public static DateTime UNIXToDateTime(int UNIXTimeStamp)
|
2014-04-14 02:29:13 +00:00
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
|
|
|
|
|
}
|
2012-08-03 01:45:38 +00:00
|
|
|
|
2016-09-02 18:46:55 +01:00
|
|
|
public static DateTime UNIXToDateTime(long UNIXTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 22:25:26 +01:00
|
|
|
public static DateTime UNIXUnsignedToDateTime(uint UNIXTimeStamp)
|
2014-04-14 02:29:13 +00:00
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
|
|
|
|
|
}
|
2012-08-03 01:45:38 +00:00
|
|
|
|
2016-09-02 06:49:59 +01:00
|
|
|
public static DateTime UNIXUnsignedToDateTime(uint seconds, uint nanoseconds)
|
|
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddSeconds(seconds).AddTicks((long)nanoseconds / 100);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-02 18:46:55 +01:00
|
|
|
public static DateTime UNIXUnsignedToDateTime(ulong UNIXTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-08 22:47:09 +01:00
|
|
|
public static DateTime HighSierraToDateTime(byte[] VDDateTime)
|
|
|
|
|
{
|
|
|
|
|
byte[] isotime = new byte[17];
|
|
|
|
|
Array.Copy(VDDateTime, 0, isotime, 0, 16);
|
|
|
|
|
return ISO9660ToDateTime(isotime);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-13 21:50:10 +01:00
|
|
|
// TODO: Timezone
|
2014-04-14 02:29:13 +00:00
|
|
|
public static DateTime ISO9660ToDateTime(byte[] VDDateTime)
|
|
|
|
|
{
|
|
|
|
|
int year, month, day, hour, minute, second, hundredths;
|
|
|
|
|
byte[] twocharvalue = new byte[2];
|
|
|
|
|
byte[] fourcharvalue = new byte[4];
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
fourcharvalue[0] = VDDateTime[0];
|
|
|
|
|
fourcharvalue[1] = VDDateTime[1];
|
|
|
|
|
fourcharvalue[2] = VDDateTime[2];
|
|
|
|
|
fourcharvalue[3] = VDDateTime[3];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "year = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(fourcharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(fourcharvalue, Encoding.ASCII), out year)) year = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// year = Convert.ToInt32(StringHandlers.CToString(fourcharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[4];
|
|
|
|
|
twocharvalue[1] = VDDateTime[5];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "month = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out month)) month = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// month = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[6];
|
|
|
|
|
twocharvalue[1] = VDDateTime[7];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "day = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out day)) day = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// day = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[8];
|
|
|
|
|
twocharvalue[1] = VDDateTime[9];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "hour = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out hour)) hour = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// hour = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[10];
|
|
|
|
|
twocharvalue[1] = VDDateTime[11];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "minute = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out minute)) minute = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// minute = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[12];
|
|
|
|
|
twocharvalue[1] = VDDateTime[13];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "second = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out second)) second = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// second = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
twocharvalue[0] = VDDateTime[14];
|
|
|
|
|
twocharvalue[1] = VDDateTime[15];
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler", "hundredths = \"{0}\"",
|
|
|
|
|
StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
|
|
|
|
if(!int.TryParse(StringHandlers.CToString(twocharvalue, Encoding.ASCII), out hundredths)) hundredths = 0;
|
2017-06-06 21:23:20 +01:00
|
|
|
// hundredths = Convert.ToInt32(StringHandlers.CToString(twocharvalue, Encoding.ASCII));
|
2012-08-05 16:45:15 +00:00
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("ISO9600ToDateTime handler",
|
|
|
|
|
"decodedDT = new DateTime({0}, {1}, {2}, {3}, {4}, {5}, {6}, DateTimeKind.Unspecified);",
|
|
|
|
|
year, month, day, hour, minute, second, hundredths * 10);
|
|
|
|
|
DateTime decodedDT = new DateTime(year, month, day, hour, minute, second, hundredths * 10,
|
|
|
|
|
DateTimeKind.Unspecified);
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
return decodedDT;
|
|
|
|
|
}
|
2014-04-17 03:45:02 +00:00
|
|
|
|
2014-04-14 02:29:13 +00:00
|
|
|
// C# works in UTC, VMS on Julian Date, some displacement may occur on disks created outside UTC
|
2016-07-28 22:25:26 +01:00
|
|
|
public static DateTime VMSToDateTime(ulong vmsDate)
|
2014-04-14 02:29:13 +00:00
|
|
|
{
|
|
|
|
|
double delta = vmsDate * 0.0001; // Tenths of microseconds to milliseconds, will lose some detail
|
|
|
|
|
return JulianEpoch.AddMilliseconds(delta);
|
|
|
|
|
}
|
2015-04-20 06:26:33 +01:00
|
|
|
|
2016-07-28 22:25:26 +01:00
|
|
|
public static DateTime AmigaToDateTime(uint days, uint minutes, uint ticks)
|
2015-04-20 06:26:33 +01:00
|
|
|
{
|
|
|
|
|
DateTime temp = AmigaEpoch.AddDays(days);
|
|
|
|
|
temp = temp.AddMinutes(minutes);
|
|
|
|
|
return temp.AddMilliseconds(ticks * 20);
|
|
|
|
|
}
|
2016-07-31 20:56:53 +01:00
|
|
|
|
|
|
|
|
public static DateTime UCSDPascalToDateTime(short dateRecord)
|
|
|
|
|
{
|
|
|
|
|
int year = ((dateRecord & 0xFE00) >> 9) + 1900;
|
|
|
|
|
int day = (dateRecord & 0x01F0) >> 4;
|
2017-12-20 17:26:28 +00:00
|
|
|
int month = dateRecord & 0x000F;
|
2016-07-31 20:56:53 +01:00
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("UCSDPascalToDateTime handler",
|
|
|
|
|
"dateRecord = 0x{0:X4}, year = {1}, month = {2}, day = {3}", dateRecord, year,
|
|
|
|
|
month, day);
|
2016-07-31 20:56:53 +01:00
|
|
|
return new DateTime(year, month, day);
|
|
|
|
|
}
|
2016-08-07 04:35:32 +01:00
|
|
|
|
|
|
|
|
public static DateTime DOSToDateTime(ushort date, ushort time)
|
|
|
|
|
{
|
|
|
|
|
int year = ((date & 0xFE00) >> 9) + 1980;
|
|
|
|
|
int month = (date & 0x1E0) >> 5;
|
|
|
|
|
int day = date & 0x1F;
|
|
|
|
|
int hour = (time & 0xF800) >> 11;
|
|
|
|
|
int minute = (time & 0x7E0) >> 5;
|
|
|
|
|
int second = (time & 0x1F) * 2;
|
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("DOSToDateTime handler", "date = 0x{0:X4}, year = {1}, month = {2}, day = {3}",
|
|
|
|
|
date, year, month, day);
|
|
|
|
|
DicConsole.DebugWriteLine("DOSToDateTime handler",
|
|
|
|
|
"time = 0x{0:X4}, hour = {1}, minute = {2}, second = {3}", time, hour, minute,
|
|
|
|
|
second);
|
2017-07-19 05:19:28 +01:00
|
|
|
|
|
|
|
|
DateTime dosdate;
|
2017-12-19 20:33:03 +00:00
|
|
|
try { dosdate = new DateTime(year, month, day, hour, minute, second); }
|
|
|
|
|
catch(ArgumentOutOfRangeException) { dosdate = new DateTime(1980, 1, 1, 0, 0, 0); }
|
2017-07-19 05:19:28 +01:00
|
|
|
|
|
|
|
|
return dosdate;
|
2016-08-07 04:35:32 +01:00
|
|
|
}
|
2016-08-26 01:43:15 +01:00
|
|
|
|
|
|
|
|
public static DateTime CPMToDateTime(byte[] timestamp)
|
|
|
|
|
{
|
|
|
|
|
ushort days = BitConverter.ToUInt16(timestamp, 0);
|
|
|
|
|
int hours = timestamp[2];
|
|
|
|
|
int minutes = timestamp[3];
|
|
|
|
|
|
|
|
|
|
DateTime temp = AmigaEpoch.AddDays(days);
|
|
|
|
|
temp = temp.AddHours(hours);
|
|
|
|
|
temp = temp.AddMinutes(minutes);
|
|
|
|
|
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
2016-09-05 21:22:04 +01:00
|
|
|
|
|
|
|
|
public static DateTime AppleDoubleToDateTime(ulong AppleDoubleTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return AppleDoubleEpoch.AddSeconds(AppleDoubleTimeStamp);
|
|
|
|
|
}
|
2016-09-15 01:54:13 +01:00
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
public static DateTime ECMAToDateTime(ushort typeAndTimeZone, short year, byte month, byte day, byte hour,
|
|
|
|
|
byte minute, byte second, byte centiseconds, byte hundredsOfMicroseconds,
|
|
|
|
|
byte microseconds)
|
2016-09-15 01:54:13 +01:00
|
|
|
{
|
|
|
|
|
byte specification = (byte)((typeAndTimeZone & 0xF000) >> 12);
|
|
|
|
|
long ticks = (long)centiseconds * 100000 + (long)hundredsOfMicroseconds * 1000 + (long)microseconds * 10;
|
|
|
|
|
if(specification == 0)
|
|
|
|
|
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(ticks);
|
|
|
|
|
|
|
|
|
|
ushort preOffset = (ushort)(typeAndTimeZone & 0xFFF);
|
|
|
|
|
short offset;
|
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
if((preOffset & 0x800) == 0x800) { offset = (short)(preOffset | 0xF000); }
|
|
|
|
|
else offset = (short)(preOffset & 0x7FF);
|
2016-09-15 01:54:13 +01:00
|
|
|
|
|
|
|
|
if(offset == -2047)
|
|
|
|
|
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified).AddTicks(ticks);
|
2017-09-14 02:01:43 +01:00
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
if(offset < -1440 || offset > 1440) offset = 0;
|
2016-09-15 01:54:13 +01:00
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
return new DateTimeOffset(year, month, day, hour, minute, second, new TimeSpan(0, offset, 0))
|
|
|
|
|
.AddTicks(ticks).DateTime;
|
2016-09-15 01:54:13 +01:00
|
|
|
}
|
2016-09-18 05:09:02 +01:00
|
|
|
|
|
|
|
|
public static DateTime UNIXHrTimeToDateTime(ulong HRTimeStamp)
|
|
|
|
|
{
|
|
|
|
|
return UNIXEpoch.AddTicks((long)(HRTimeStamp / 100));
|
|
|
|
|
}
|
2017-08-16 15:45:15 +01:00
|
|
|
|
|
|
|
|
public static DateTime OS9ToDateTime(byte[] date)
|
|
|
|
|
{
|
2017-12-20 17:26:28 +00:00
|
|
|
if(date == null || date.Length != 3 && date.Length != 5) return DateTime.MinValue;
|
2017-08-16 15:45:15 +01:00
|
|
|
|
|
|
|
|
DateTime os9date;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-12-19 20:33:03 +00:00
|
|
|
os9date = date.Length == 5
|
|
|
|
|
? new DateTime(1900 + date[0], date[1], date[2], date[3], date[4], 0)
|
|
|
|
|
: new DateTime(1900 + date[0], date[1], date[2], 0, 0, 0);
|
2017-08-16 15:45:15 +01:00
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
catch(ArgumentOutOfRangeException) { os9date = new DateTime(1900, 0, 0, 0, 0, 0); }
|
2017-08-16 15:45:15 +01:00
|
|
|
|
|
|
|
|
return os9date;
|
|
|
|
|
}
|
2017-09-14 02:01:43 +01:00
|
|
|
|
|
|
|
|
public static DateTime LifToDateTime(byte[] date)
|
|
|
|
|
{
|
2017-12-19 20:33:03 +00:00
|
|
|
if(date == null || date.Length != 6) return new DateTime(1970, 1, 1, 0, 0, 0);
|
2017-09-14 02:01:43 +01:00
|
|
|
|
|
|
|
|
return LifToDateTime(date[0], date[1], date[2], date[3], date[4], date[5]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static DateTime LifToDateTime(byte year, byte month, byte day, byte hour, byte minute, byte second)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-12-20 17:26:28 +00:00
|
|
|
int iyear = (year >> 4) * 10 + (year & 0xF);
|
2017-09-14 02:01:43 +01:00
|
|
|
int imonth = (month >> 4) * 10 + (month & 0xF);
|
|
|
|
|
int iday = (day >> 4) * 10 + (day & 0xF);
|
|
|
|
|
int iminute = (minute >> 4) * 10 + (minute & 0xF);
|
|
|
|
|
int ihour = (hour >> 4) * 10 + (hour & 0xF);
|
|
|
|
|
int isecond = (second >> 4) * 10 + (second & 0xF);
|
|
|
|
|
|
2017-12-19 20:33:03 +00:00
|
|
|
if(iyear >= 70) iyear += 1900;
|
|
|
|
|
else iyear += 2000;
|
2017-09-14 02:01:43 +01:00
|
|
|
|
|
|
|
|
return new DateTime(iyear, imonth, iday, ihour, iminute, isecond);
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
catch(ArgumentOutOfRangeException) { return new DateTime(1970, 1, 1, 0, 0, 0); }
|
2017-09-14 02:01:43 +01:00
|
|
|
}
|
2014-04-14 02:29:13 +00:00
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|