[15] Windows では NTFS などで整数時刻系が使われています。
[7] Why is the Win32 epoch January 1, 1601? – The Old New Thing () https://blogs.msdn.microsoft.com/oldnewthing/20090306-00/?p=18913
[8] date - What is the significance of January 1, 1601? - Stack Overflow () http://stackoverflow.com/questions/10849717/what-is-the-significance-of-january-1-1601
Active Directory stores date/time values as the number of 100-nanosecond intervals that have elapsed since the 0 hour on January 1, 1601 until the date/time that is being stored. The time is always stored in UTC (Coordinated Universal Time, which used to be called Greenwich Mean Time, or GMT) in the Active Directory.
NT time is number of 100-nanoseconds since 1601-01-01 00:00:00 UTC.
【LastLogonTimeStamp】属性にはNTタイムエポック値という値で記録される。
NTタイムエポック値とは、1601/01/01 00:00:00 から100ナノ秒単位のカウント値である。
[25] 符号無し整数と解説されることが多いようですが、 Windows の関係する API は符号付き整数としているものもあれば、 符号無し整数としているものもあり、 一貫していないところがあるようです。
[26] Windows で実際に正常に取り扱えるのは、他の API やデータ構造の関係もあり、 更に限定された範囲になるようです。
[27] また、値 0 が特殊値として使われることがあるようです。
[28] あまりに大きな数値のため、値域の両端の年月日を一般的な日時処理の実装では正確に扱えないことがあります。 そのためもあるのか、両端の値を記述していない解説も多く、記載していても他の資料と微妙に違う値のこともあります。
[29] そこで ChatGPT に両端の日時を正確に計算するプログラムを作成させました。 >>30 これによって得られた結果は、 次の通りです。すべて先発グレゴリオ暦 / 先発UTC / 閏秒のないUTCの日時です。
-27627-04-19T21:11:54.522419200Z -30828-09-14T02:48:05.477580700Z +01601-01-01T00:00:00.000000000Z +60056-05-28T05:36:10.955161500Z # 64-bit NTFS 時刻を正確に年・月・日・時・分・秒・ナノ秒に変換する(整数演算)
def ntfs_to_human(ntfs_time):
"""
NTFS 64bit 時刻 (100ns単位) -> 年, 月, 日, 時, 分, 秒, ナノ秒
"""
# 基準日 1601-01-01
base_year = 1601
# 100ns -> 秒とナノ秒
total_seconds, remainder_100ns = divmod(ntfs_time, 10_000_000)
nano = remainder_100ns * 100
# 秒 -> 日 + 秒
days, seconds_of_day = divmod(total_seconds, 86400)
hours, rem = divmod(seconds_of_day, 3600)
minutes, sec = divmod(rem, 60)
# グレゴリオ暦400年周期
days_remaining = days
# 400年 = 146097日
n400, days_remaining = divmod(days_remaining, 146097)
year = base_year + n400 * 400
# 100年周期(ただし400年周期の最初の100年は閏年扱い注意)
n100, days_remaining = divmod(days_remaining, 36524) # 100年 = 36524日 (100年周期のうるう年除外)
if n100 == 4: # 400年ごとの最後の100年補正
n100 = 3
days_remaining += 36524
year += n100 * 100
# 4年周期
n4, days_remaining = divmod(days_remaining, 1461) # 4年 = 1461日
year += n4 * 4
# 1年周期
n1, days_remaining = divmod(days_remaining, 365)
if n1 == 4: # 4年周期の最後の年補正
n1 = 3
days_remaining += 365
year += n1
# 閏年判定
is_leap = (year % 4 == 0 and (year % 100 != 0 or year % 400 == 0))
# 月・日計算
month_days = [31, 29 if is_leap else 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31]
month = 1
for md in month_days:
if days_remaining < md:
day = days_remaining + 1
break
days_remaining -= md
month += 1
return year, month, day, hours, minutes, sec, nano
# signed / unsigned 64-bit 最大・最小値
signed_min = -2**63
signed_max = 2**63 - 1
unsigned_min = 0
unsigned_max = 2**64 - 1
# 計算
smin_human = ntfs_to_human(signed_min)
smax_human = ntfs_to_human(signed_max)
umin_human = ntfs_to_human(unsigned_min)
umax_human = ntfs_to_human(unsigned_max)
smin_human, smax_human, umin_human, umax_human[37] [MS-DTYP]: FILETIME | Microsoft Learn, , https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/2c57429b-fdd4-488f-b5fc-9e4cf020fcdf
dwLowDateTime: A 32-bit unsigned integer that contains the low-order bits of the file time.
dwHighDateTime: A 32-bit unsigned integer that contains the high-order bits of the file time.
[17] Interpretation of NTFS Timestamps - Forensic Focus, Forensic Focus, https://www.forensicfocus.com/articles/interpretation-of-ntfs-timestamps/
[18] Interpretation of NTFS Timestamps - Forensic Focus, Forensic Focus, https://www.forensicfocus.com/articles/interpretation-of-ntfs-timestamps/
The documentation of FileTimeToSystemTime(), as well as practical tests, indicate that the FILETIME value to be translated must be 0x7FFFFFFFFFFFFFFF or less. This corresponds to the time 30828-09-14 02:48:05.4775807.
These system calls have a similar limitation in that only timestamps less than or equal to 0x7fffffffffffffff will be set. Additionally, the two timestamp values 0x0 and 0xffffffffffffffff are reserved to modify the operation of the system call in different ways.
The reverse function, SystemTimeToFileTime(), performs the opposite conversion: translating a time expressed as the year, month, day, hours, minutes, seconds, etc into the 64-bit file time stamp. In this case, however, the span of time is restricted to years less than or equal to 30827.
[19] c++ - Latest possible FILETIME - Stack Overflow, https://stackoverflow.com/questions/9999393/latest-possible-filetime
My understanding is that
FILETIMEwas made to represent any validSYSTEMTIMEin 64 bits. If you take the limit ofSYSTEMTIME(last millisecond in 30827) then you end up with aFILETIMEof0x7fff35f4f06c58f0by usingSystemTimeToFileTime().However, if you put
0x7fffffffffffffffintoFileTimeToSystemTime()then you will end up in the year 30828, although this date is invalid forSYSTEMTIME. Any larger value (0x8000000000000000and above) causesFileTimeToSystemTime()to fail.
[20] Windowsのファイル時刻を扱うためのライブラリを作成した話, https://zenn.dev/sorairolake/articles/introduction-of-nt-time
最大値は60056年5月28日5時36分10秒955161500 (UTC) ですが、WindowsのAPIでは最大値は64ビット符号付き整数の最大値に制限されます。
FileTime::MAX-FileTimeが表すことのできる最大値 (+60056-05-28 05:36:10.955161500 UTC) を表します
Microsoft Windows NTでは1601年1月1日0時0分(UTC)(先発グレゴリオ暦)からの100ナノ秒ティック単位での経過時間が主に用いられる。ただし後者は、現在時刻を最も近いミリ秒の値に近似している。
NTFSではファイルの時刻を1601年1月1日起点の64bitの経過時間で持っています。時間の単位は0.1μ秒です。1601年1月1日0時0分0秒の2**64=1844674407370.9551616秒後は60056年5月28日5時36分10.9551616秒になります。
FILETIME構造体は次のように定義された 1601 年 1 月 1 日午前 12 時からの 100 ナノ秒間隔の数 (UTC)を表す64ビット整数である。
Windows 2003 ServerのActiveDirectory(Windowsすべての日付がそうなのかは不明ですが)上の日付というのは1601年1月1日から100ナノ秒(10000000分の1秒?)間隔というワケのワカラン仕様なのです
A Windows file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC). Windows uses a file time to record when an application creates, accesses, or writes to a file.
Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
[16] Time formatting and storage bugs - Wikipedia, , https://en.wikipedia.org/wiki/Time_formatting_and_storage_bugs#Year_30,828
Beginning 14 September 30,828, Windows will not accept dates beyond this day and on startup, it will display an error regarding "invalid system time" in NTFS. This is because the FILETIME value in Windows, which is a 64-bit value corresponding to the number of 100-nanosecond intervals since 1 January 1601, 00:00:00.0000000 UTC, will overflow its maximum possible value on that day at 02:48:05.4775808 UTC.
[23] Test Cases for the RTC Real-Time Functions Test | Microsoft Learn, , https://learn.microsoft.com/en-us/previous-versions/windows/embedded/bb330911(v=winembedded.60)?redirectedfrom=MSDN
The test looks for the range beginning with the minimum possible FILETIME (FILETIME 0 is the start of Jan 1st 1601) and end with maximum possible FILETIME (Max FILETIME is the maximum 64-bit value).
ActiveDirectryの情報をPerlで取得したりすると、最終ログイン日時やパスワード変更日時が上記の秒数になって表示されているので、変換する必要があります。
A Mail::Exchange::Time object allows you to convert between unix time and the time used internally in by Microsoft, which is defined as number of 100-nsec-intervals since Jan 01, 1901.