Mac HFS+ Timestamp Converter
Convert HFS+ seconds (since 1904-01-01 UTC) to human-readable dates — and back. Accepts hex (0x…) or decimal. Fully client-side.
Related Tools
UNIX Timestamp Converter · Apple Cocoa / Core Foundation Time · LDAP / FILETIME Converter · Unix Hex Timestamp
Results always include UTC; this controls the extra local view.
UNIX ↔ HFS+ offset:
2,082,844,800
seconds (to/from 1970-01-01 UTC)1) HFS+ Seconds → Date
Hex with/without
0x
is accepted. Negative values supported.
11 22 33 44
read little-endian, toggle swap.
2) Date → HFS+ Seconds
Interpreted in your current local time zone.
If an offset is provided, it will be respected.
About HFS+ Time
HFS+ stores timestamps as whole seconds since the Mac epoch 1904-01-01T00:00:00Z. Compared to UNIX (1970-01-01T00:00:00Z), the exact gap is 2,082,844,800 seconds.
- HFS+ → UNIX seconds:
unix = hfs - 2,082,844,800
- UNIX seconds → HFS+:
hfs = unix + 2,082,844,800
- Endianness: On-disk HFS+ structures are big-endian; byte order matters when reading raw bytes.
- Range: Classic 32-bit fields wrap at
2^32
(≈ 2106-02-07 for UNIX).
HFS+ Time: Code Snippets
Copy-ready examples for converting between HFS+ seconds (since 1904-01-01 UTC) and human time.
Swift
let HFS_OFFSET: TimeInterval = 2_082_844_800 // seconds
func hfsToDate(_ hfs: TimeInterval) -> Date { Date(timeIntervalSince1970: hfs - HFS_OFFSET) }
func dateToHfs(_ date: Date) -> TimeInterval { date.timeIntervalSince1970 + HFS_OFFSET }
// Hex helper
func parseHexOrDec(_ s: String) -> Int64 {
let t = s.trimmingCharacters(in: .whitespacesAndNewlines)
if t.lowercased().hasPrefix("0x") { return Int64(t.dropFirst(2), radix:16)! }
if t.range(of: "[a-fA-F]", options:.regularExpression) != nil { return Int64(t, radix:16)! }
return Int64(t)!
}
Objective-C
static const NSTimeInterval kHFSOffset = 2082844800.0;
NSDate * HFSPlusToDate(long long hfs){ return [NSDate dateWithTimeIntervalSince1970:(hfs - kHFSOffset)]; }
long long DateToHFSPlus(NSDate *d){ return llround([d timeIntervalSince1970] + kHFSOffset); }
JavaScript
const HFS_OFFSET = 2082844800n; // seconds
function floorDiv(a,b){ const q=a/b, r=a%b; return r===0n || (a>=0n)===(b>=0n) ? q : q-1n; }
function parseIntFlexible(s){
s = s.trim();
if (/^-?0x[0-9a-f]+$/i.test(s)) return BigInt(s);
if (/^-?[0-9a-f]+$/i.test(s) && /[a-f]/i.test(s)) return BigInt((s[0]==='-'?'-':'') + '0x' + s.replace(/^-/,''));
if (/^-?\d+$/.test(s)) return BigInt(s);
throw new Error('bad int');
}
function hfsToDate(s){ const hfs = parseIntFlexible(s); const ms = (hfs - HFS_OFFSET) * 1000n; return new Date(Number(ms)); }
function dateToHfs(d=new Date()){ const ms=BigInt(d.getTime()); const sec=floorDiv(ms,1000n); return (sec + HFS_OFFSET).toString(); }
Python
import datetime, re
HFS_OFFSET = 2_082_844_800
def parse_int_flexible(s:str)->int:
s=s.strip()
if s.lower().startswith('-0x'): return -int(s[3:],16)
if s.lower().startswith('0x'): return int(s[2:],16)
if re.search(r'[a-f]', s, re.I): return int(s,16)
return int(s,10)
def hfs_to_datetime(v:int)->datetime.datetime:
return datetime.datetime.fromtimestamp(v - HFS_OFFSET, tz=datetime.timezone.utc)
def datetime_to_hfs(dt:datetime.datetime)->int:
if dt.tzinfo is None: dt = dt.astimezone()
return int(dt.timestamp()) + HFS_OFFSET
C (32-bit unsigned view)
#include <time.h> #include <stdint.h>
#define HFS_OFFSET 2082844800u
time_t hfs_to_unix(uint32_t hfs){ return (time_t)((uint32_t)hfs - HFS_OFFSET); }
uint32_t unix_to_hfs(time_t unix){ return (uint32_t)(unix + HFS_OFFSET); }
Byte-swap tip
If a 4-byte hex was read little-endian (e.g., 44 33 22 11
) but HFS+ expects big-endian, swap to 11223344
before converting.