The Python code demonstrates how to convert between Unix epoch and Windows epoch, both ways.
The functions win_to_unix_epoch() and unix_to_win_epoch(), available for scrutiny in the Perl source code, demonstrate how to convert between Windows and Unix epoch, both ways.
There's a "magic number" of seconds that makes up the difference between the Windows and Unix epoch (11644473600).
If you provide a nanosecond timestamp, get a date, and convert it back to a nanosecond timestamp, you will notice that you lose precision beyond seconds. This is a limitation due to how the programs work with seconds at some points.PS C:\> .\Conv-WinTime.exe Usage: Conv-WinTime.exe [--help] [--nano2human "100th nanoseconds"] [--human2nano "year-month-day hour:minute:second"] --help : Print this help text. --nano2human : Enter 100th nanoseconds as used by for instance the lastLogon LDAP/AD attribute on Windows, and get a human- readable date back. --human2nano : Enter a human-readable date in the format: "year-month-day hour:minute:second", and get the 100th nanosecond timestamp back.Author: Joakim Svendsen, "joakimbs" using Google's mail service.
ERROR: Please specify either --nano2human, --human2nano or both
PS C:\> perl .\Conv-WinTime.pl --human2nano '2012-12-24 00:00:00' Date: 2012-12-24 00:00:00 | 100th ns (Wintime): 130007772000000000
And to convert it back:
PS C:\> .\Conv-WinTime.exe --nano2human 130007772000000000 100th ns (Wintime): 130007772000000000 | Date: 2012-12-24 00:00:00
To get a little more fancy, and involve PowerShell, you can convert multiple dates to nanosecond timestamps (or the other way around) like this (or similarly):
PS C:\> '2012-12-24 00:00:00', '2013-12-24 00:00:00' | %{ .\Conv-WinTime.exe --human2nano $_ } Date: 2012-12-24 00:00:00 | 100th ns (Wintime): 130007772000000000 Date: 2013-12-24 00:00:00 | 100th ns (Wintime): 130323132000000000
A custom-formatted Get-Date will also do:
PS C:\> Get-Date -uformat '%Y-%m-%d %H:%M:%S' | %{ .\Conv-WinTime.exe --human2nano $_ } Date: 2012-03-17 15:05:30 | 100th ns (Wintime): 129764667300000000
To get just the nanoseconds without all the other stuff, you can do it in a ton of ways. This one's probably the simplest, using the -split operator and array indexing to get the last whitespace-separated element, indexed by [-1]:
PS C:\> '2012-12-24 00:00:00', '2013-12-24 00:00:00' | >> %{ ((.\Conv-WinTime.exe --human2nano $_) -split '\s+')[-1] } >> 130007772000000000 130323132000000000
use warnings; use strict; use Getopt::Long; use File::Basename; use Time::Local; our $VERSION = '1.01'; my $debug = 1;main();
sub main { my %opt; GetOptions('help' => \$opt{help}, 'nano2human=s' => \$opt{nano2human}, 'human2nano=s' => \$opt{human2nano}, ) or die "Errors encountered while parsing command line options: $! -- $^E\n"; parse_args(\%opt); if ($opt{nano2human}) { print_help("Malformed nano time (non-digits found): $opt{nano2human}\n") if $opt{nano2human} =~ /\D/; nano2human($opt{nano2human}); } if ($opt{human2nano}) { human2nano($opt{human2nano}); } } sub print_help { my @message = @_; my $script_name = basename $0; print <Author: Joakim Borger Svendsen, Svendsen Tech, svendsentech@gmail.com MIT License. EOF print @message, "\n" if @message; exit; } sub nano2human { my $wintime = shift; my $unix_epoch = win_to_unix_epoch($wintime); my ($year, $month, $day, $hour, $minute, $second) = (localtime $unix_epoch)[5,4,3,2,1,0]; $year += 1900; $month += 1; ($month, $day, $hour, $minute, $second) = map { sprintf '%02d', $_ } $month, $day, $hour, $minute, $second; print "100th ns (Wintime): $wintime | Date: " . join('-', $year, $month, $day) . ' ' . join(':', $hour, $minute, $second); print "\n"; } sub human2nano { my $date = shift; if ($date =~ /^(\d{4})-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)$/) { my ($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3, $4, $5, $6); # Conform to localtime() standards as used by Time::Local $year -= 1900; $month -= 1; my $unix_epoch = timelocal($second, $minute, $hour, $day, $month, $year); my $win_epoch = unix_to_win_epoch($unix_epoch); print "Date: $date | 100th ns (Wintime): $win_epoch\n"; } else { print_help(qq{ERROR: Malformed date specified: $date\nValid example: '2000-12-24 20:00:00'.\nRemember double quotes ("") around the --human2nano argument}); } } sub parse_args { my $opt = shift; print_help('') if $opt->{help}; unless ($opt->{nano2human} or $opt->{human2nano}) { print_help("Warning: Please specify either --nano2human, --human2nano or both\n"); } } sub win_to_unix_epoch { # Actually hundreths of nanoseconds at this point... my $nanoseconds = shift; # Get seconds my $seconds = $nanoseconds / 10_000_000; # This magic number is the difference between Unix and Windows epoch. my $unix_epoch = $seconds - 11644473600; # Return the Unix epoch for use with localtime(). return $unix_epoch; } sub unix_to_win_epoch { my $unix_epoch = shift; my $winseconds = $unix_epoch + 11644473600; my $win_epoch = sprintf '%.0f', ($winseconds * 10_000_000); return $win_epoch; }
Here it is in action:
PS E:\Python> .\Conv-WinTime.py --date2nano '2013-01-01T00:00:00' 130014684000000000
Convert it back and verify it's correct:
PS E:\Python> .\Conv-WinTime.py --nano2date 130014684000000000 2013-01-01 00:00:00
Use PowerShell for this near "noop" operation ("it does nothing"), to further verify it works as expected:
PS E:\Python> [datetime]::FromFileTime( (.\Conv-WinTime.py --date2nano '2013-01-01T00:00:00') ) 01 January, 2013 00:00:00
*Conv-WinTimePy.txt (right-click and save, rename to .py).
#!/usr/bin/env python import datetime import calendar import time import sys import re from optparse import OptionParser # Author: Joakim Svendsen, "joakimbs" using Google's mail services. # Copyright (c) 2013. Svendsen Tech. All rights reserved. # BSD 3-clause license. parser = OptionParser() parser.add_option("-n", "--nano2date", type="long", dest="nano_time", help="Specify a Windows nanosecond (AD) timestamp to convert to a date/time.") parser.add_option("-d", "--date2nano", dest="human_datetime", help="Specify a date and time string in the format: \"yyyy-MM-ddTHH:mm:ss\" to be converted to a \ Windows nanosecond (AD) timestamp. Example: \"2013-01-01T17:00:00\"")Perl(options, args) = parser.parse_args()
if options.nano_time: seconds = options.nano_time / 10000000 epoch = seconds - 11644473600 dt = datetime.datetime(2000, 1, 1, 0, 0, 0) print dt.fromtimestamp(epoch) if options.human_datetime: m = re.compile(r'^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$').match(options.human_datetime) if m: dt = datetime.datetime(*map(int, m.groups())) #unix_timestamp = time.mktime(dt.timetuple()) windows_timestamp = long((time.mktime(dt.timetuple()) + 11644473600) * 10000000) print windows_timestamp else: print "Invalid date format specified with --date2nano: " + options.human_datetime + \ ".\nUse the --help parameter for more information."
Minimum cookies is the standard setting. This website uses Google Analytics and Google Ads, and these products may set cookies. By continuing to use this website, you accept this.