This article was originally posted to my old WordPress blog.

Formatting and converting dates can be very confusing. Every programming language, operating system, and runtime environment seem to do it differently. And part of the difficulty in conversion is knowing what units you are starting with. First, it is helpful to know the Epoch (or starting date) a stored value is based on. Wikipedia has a good article on this. Here is a brief excerpt.

Epoch dateNotable usesRationale for selection
January 1, AD 1Microsoft .NETCommon Era, ISO 2014, RFC 3339
January 1, 1601NTFS, COBOL, Win32/Win641601 was the first year of the 400-year Gregorian calendar cycle at the time Windows NT was made
January 0, 1900Microsoft Excel, Lotus 1-2-3While logically January 0, 1900 is equivalent to December 31, 1899, these systems do not allow users to specify the latter date.
January 1, 1904Apple Inc.’s macOS through version 91904 is the first leap year of the 20th century
January 1, 1970Unix Epoch aka POSIX time. Used by Unix and Unix-like systems (Linux, macOS X), and programming languages: most C/C++ implementations, Java, JavaScript, Perl, PHP, Python, Ruby, Tcl, ActionScript.
January 1, 1980IBM BIOS INT 1Ah, DOS, OS/2, FAT12, FAT16, FAT32, exFAT filesystemsThe IBM PC with its BIOS as well as 86-DOS, MS-DOS and PC DOS with their FAT12 file system were developed and introduced between 1980 and 1981

Common Date Conversion Tasks

  • WMI Dates

    PS> $installDate = (Get-WmiObject win32_operatingsystem | select Installdate ).InstallDate
    PS> []::ToDateTime($InstallDate)
    Friday, September 12, 2008 6:50:57 PM
    PS> [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($(get-date))
  • Excel dates - Excel stores dates as sequential serial numbers so that they can be used in calculations. By default, January 1, 1900, is serial number 1.

    PS> ((Get-Date).AddDays(1) - (get-date "12/31/1899")).Days

    In this example, the value Days is 42335 which is the serial number for 11/27/2015 in Excel. The date 12/31/1899 is equivalent to January 0, 1900. The difference between 12/31/1899 and 11/27/2015 is 42334 but since the serial numbers start a 1 you need to add 1 day to get the serial number for 11/27/2015.

  • Converting from custom string formats

    PS> $information = '12Nov(2012)18h30m17s'
    PS> $pattern = 'ddMMM\(yyyy\)HH\hmm\mss\s'
    PS> [datetime]::ParseExact($information, $pattern, $null)
    Monday, November 12, 2012 6:30:17 PM
  • FILETIME conversion - FILETIME is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).

    PS> Get-AdUser username -prop badPasswordTime,lastLogonTimestamp | select badPasswordTime, lastLogonTimestamp
    badPasswordTime : 130927962789982434
    lastLogonTimestamp : 130931333173599571
    PS> [datetime]::fromfiletime(130927962789982434)
    Monday, November 23, 2015 3:51:18 PM
    PS> [datetime]::fromfiletime(130931333173599571)
    Friday, November 27, 2015 1:28:37 PM
  • CTIME or Unix format - is an integral value representing the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC (i.e., a Unix timestamp).

    PS> $epoch = get-date "1/1/1970"
    PS> $epoch.AddMilliseconds(1448302797803)
    Monday, November 23, 2015 6:19:57 PM
    PS> $epoch.AddSeconds(1448302797.803)
    Monday, November 23, 2015 6:19:57 PM