Skip to content

Instantly share code, notes, and snippets.

@Mostafa-Hamdy-Elgiar
Created February 25, 2017 09:22
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Mostafa-Hamdy-Elgiar/9714475f1b3bc224ea063af81566d873 to your computer and use it in GitHub Desktop.
Save Mostafa-Hamdy-Elgiar/9714475f1b3bc224ea063af81566d873 to your computer and use it in GitHub Desktop.
Python Script to convert Microsoft widows file time to python date and also date to windows file time
#!/usr/bin/env python
# Copyright (c) 2009, David Buxton <david@gasmark6.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tools to convert between Python datetime instances and Microsoft times.
"""
from datetime import datetime, timedelta, tzinfo
from calendar import timegm
# http://support.microsoft.com/kb/167296
# How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
HUNDREDS_OF_NANOSECONDS = 10000000
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
def dt_to_filetime(dt):
"""Converts a datetime to Microsoft filetime format. If the object is
time zone-naive, it is forced to UTC before conversion.
>>> "%.0f" % dt_to_filetime(datetime(2009, 7, 25, 23, 0))
'128930364000000000'
>>> dt_to_filetime(datetime(1970, 1, 1, 0, 0, tzinfo=utc))
116444736000000000L
>>> dt_to_filetime(datetime(1970, 1, 1, 0, 0))
116444736000000000L
"""
if (dt.tzinfo is None) or (dt.tzinfo.utcoffset(dt) is None):
dt = dt.replace(tzinfo=utc)
return EPOCH_AS_FILETIME + (timegm(dt.timetuple()) * HUNDREDS_OF_NANOSECONDS)
def filetime_to_dt(ft):
"""Converts a Microsoft filetime number to a Python datetime. The new
datetime object is time zone-naive but is equivalent to tzinfo=utc.
>>> filetime_to_dt(116444736000000000)
datetime.datetime(1970, 1, 1, 0, 0)
>>> filetime_to_dt(128930364000000000)
datetime.datetime(2009, 7, 25, 23, 0)
"""
return datetime.utcfromtimestamp((ft - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS)
if __name__ == "__main__":
import doctest
doctest.testmod()
@Mostafa-Hamdy-Elgiar
Copy link
Author

Usage :
#python

from filetimes import filetime_to_dt, dt_to_filetime
dt_tofiletime(int(yyyy),int(mon),int(dd))

@MuhammadAbdulMoniem
Copy link

Very Helpful Script ... Thank you very much 👍

@kdschlosser
Copy link

kdschlosser commented Oct 12, 2018

I wanted to say thank you for posting this code. Very handy. I did create a version inspired by this post and I wanted to share it.
It adds more flexibility in it's use.. read the comments it will explain what it's all about

I did not add the UTC conversions and I am sure that they can be very easily added.

# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright © 2005-2018 EventGhost Project <http://www.eventghost.org/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

# inspired by @Mostafa-Hamdy-Elgiar on GithubGist with the Filetimes.py file

from __future__ import print_function

import ctypes
from ctypes.wintypes import DWORD

from datetime import datetime
import time


# Win32 Epoch time is not the same as Unix Epoch time.
# Win32 Epoch time starts at 1/1/1601 00:00:00 where as
# Unix Epoch time starts January 1, 1970 00:00:00.
# Win32 Epoch time representation is also in hundreds of nanoseconds.
# So we need to have a couple of offsets to make the conversions

# this is the Win32 Epoch time for when Unix Epoch time started. It is in
# hundreds of nanoseconds.
EPOCH_AS_FILETIME = 116444736000000000

# This is the divider/multiplier for converting nanoseconds to
# seconds and vice versa
HUNDREDS_OF_NANOSECONDS = 10000000



# I coded this in a way that is going to make doing these time conversions
# really easy. The FILETIME class is a python version of the
# C Windows datatype structure. this can be used for this purpose for setting
# and getting filetimes. This class can be constructed with no values passed.
# then using ctypes.byref() the instance can be passed to the
# Kernel32.GetFileTime function. then by using one of the properties the
# conversions are made.

# You can also supply values on construction so the class can be passed to
# set the filetime as well.
# the constructor accepts 2 parameters. Most of the time you will only pass a
# single value. The values passed can be

# low byte 32 bit integer, high byte 32bit integer

# this is what Windows uses and stores in this structure. I did this so if
# needed the values can be set

# 64 bit integer (long)
# this can be either a float/int of the Unix Epoch time,
# or the Windows Epoch Time. an easy way of getting the time and passing it
# FILETIME(time.time())

# time.time_struct instance
# This example you would not do but for the sake of example the time.time()
# returns the current time since the Unix Epoch in float(seconds). the
# time.localtime() accepts the float and returns a time.time_struct instance
# so if you were storing times for some reason. you could store them as
# int/float(seconds) and using localtime create the time.time_struct instance.
# FILETIME(time.localtime(time.time()))

# datetime.datetime instance,
# same kind of a thing as the above 2 examples.
# FILETIME(datetime.datetime.now())

# passing anything to the constructor is almost only going to be done if you
# are going to set the file time

# properties.
# unix_epoch_seconds
#      number of seconds since the Unix Epoch
# windows_epoch_seconds
#      number of seconds since the Windows Epoch
# unix_epoch_datetime
#      datetime.datetime instance
# seconds
#      same as unix_epoch_seconds
# minutes
#      number of minutes since Unix Epoch
# hours
#      number of hours since Unix Epoch
# days
#      number of days since Unix Epoch
# int(instance)
#      same as unix_epoch_seconds
# float(instance)
#      unix_epoch_seconds with fractions of a second
# str(instance)
#      formatted string representation of the time for your locale.


class _FILETIME(ctypes.Structure):
    _fields_ = [
        ('dwLowDateTime', DWORD),
        ('dwHighDateTime', DWORD)
    ]

    def __init__(self, dwLowDateTime=None, dwHighDateTime=None):

        if dwLowDateTime is None and dwHighDateTime is None:
            super(_FILETIME, self).__init__()

        else:
            if dwHighDateTime is None:
                if isinstance(dwLowDateTime, datetime):
                    dwLowDateTime = time.mktime(datetime.now().timetuple())

                elif isinstance(dwLowDateTime, time.struct_time):
                    dwLowDateTime = time.mktime(dwLowDateTime)

                else:
                    try:
                        dwLowDateTime = dwLowDateTime.seconds
                    except AttributeError:
                        pass

                dwLowDateTime = int(dwLowDateTime)
                if (
                    (dwLowDateTime - EPOCH_AS_FILETIME) /
                    HUNDREDS_OF_NANOSECONDS < 0
                ):
                    dwLowDateTime = (
                        (dwLowDateTime * HUNDREDS_OF_NANOSECONDS) +
                        EPOCH_AS_FILETIME
                    )

                dwHighDateTime = (dwLowDateTime >> 32)
                dwLowDateTime = dwLowDateTime - ((dwLowDateTime >> 32) << 32)

            self.dwLowDateTime = DWORD(dwLowDateTime)
            self.dwHighDateTime = DWORD(dwHighDateTime)

            super(_FILETIME, self).__init__(dwLowDateTime, dwHighDateTime)

    @property
    def unix_epoch_seconds(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return (val - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS

    @property
    def windows_epoch_seconds(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return val / HUNDREDS_OF_NANOSECONDS

    @property
    def unix_epoch_datetime(self):
        return datetime.utcfromtimestamp(self.unix_epoch_seconds)

    @property
    def seconds(self):
        return self.unix_epoch_seconds

    @property
    def minutes(self):
        return int(self.seconds / 60)

    @property
    def hours(self):
        return int(self.minutes / 60)

    @property
    def days(self):
        return int(self.hours / 24)

    def __int__(self):
        return self.unix_epoch_seconds

    def __float__(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return (val - EPOCH_AS_FILETIME) / float(HUNDREDS_OF_NANOSECONDS)

    def __str__(self):
        dt = datetime.utcfromtimestamp(self.unix_epoch_seconds)
        return dt.strftime('%c')


FILETIME = _FILETIME
PFILETIME = ctypes.POINTER(_FILETIME)


if __name__ == '__main__':

    i = time.time()
    j = (int(i) * HUNDREDS_OF_NANOSECONDS) + EPOCH_AS_FILETIME

    k_high = (j >> 32)
    k_low = j - ((j >> 32) << 32)

    l = datetime.now()
    m = time.localtime(i)

    objs = (
        ('Unix Epoch', (i,)),
        ('Win32 Epoch (64bit)', (j,)),
        ('Win32 Epock (2 * 32bit)', (k_low, k_high)),
        ('datetime.datetime', (l,)),
        ('time.struct_time', (m,))
    )

    for time_type, values in objs:

        print(time_type, '-', values)
        ft = FILETIME(*values)
        print('  windows_epoch_seconds:', ft.windows_epoch_seconds)
        print('  unix_epoch_seconds:', ft.unix_epoch_seconds)
        print('  seconds:', ft.seconds)
        print('  minutes:', ft.minutes)
        print('  hours:', ft.hours)
        print('  days:', ft.days)
        print('  __int__:', int(ft))
        print('  __float__:', float(ft))
        print('  __str__:', str(ft))
        print('  dwHighDateTime:', ft.dwHighDateTime)
        print('  dwLowDateTime:', ft.dwLowDateTime)

        print('\n\n')

@chicco-crypto
Copy link

I wanted to say thank you for posting this code. Very handy. I did create a version inspired by this post and I wanted to share it.
It adds more flexibility in it's use.. read the comments it will explain what it's all about

I did not add the UTC conversions and I am sure that they can be very easily added.

# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright © 2005-2018 EventGhost Project <http://www.eventghost.org/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

# inspired by @Mostafa-Hamdy-Elgiar on GithubGist with the Filetimes.py file

from __future__ import print_function

import ctypes
from ctypes.wintypes import DWORD

from datetime import datetime
import time


# Win32 Epoch time is not the same as Unix Epoch time.
# Win32 Epoch time starts at 1/1/1601 00:00:00 where as
# Unix Epoch time starts January 1, 1970 00:00:00.
# Win32 Epoch time representation is also in hundreds of nanoseconds.
# So we need to have a couple of offsets to make the conversions

# this is the Win32 Epoch time for when Unix Epoch time started. It is in
# hundreds of nanoseconds.
EPOCH_AS_FILETIME = 116444736000000000

# This is the divider/multiplier for converting nanoseconds to
# seconds and vice versa
HUNDREDS_OF_NANOSECONDS = 10000000



# I coded this in a way that is going to make doing these time conversions
# really easy. The FILETIME class is a python version of the
# C Windows datatype structure. this can be used for this purpose for setting
# and getting filetimes. This class can be constructed with no values passed.
# then using ctypes.byref() the instance can be passed to the
# Kernel32.GetFileTime function. then by using one of the properties the
# conversions are made.

# You can also supply values on construction so the class can be passed to
# set the filetime as well.
# the constructor accepts 2 parameters. Most of the time you will only pass a
# single value. The values passed can be

# low byte 32 bit integer, high byte 32bit integer

# this is what Windows uses and stores in this structure. I did this so if
# needed the values can be set

# 64 bit integer (long)
# this can be either a float/int of the Unix Epoch time,
# or the Windows Epoch Time. an easy way of getting the time and passing it
# FILETIME(time.time())

# time.time_struct instance
# This example you would not do but for the sake of example the time.time()
# returns the current time since the Unix Epoch in float(seconds). the
# time.localtime() accepts the float and returns a time.time_struct instance
# so if you were storing times for some reason. you could store them as
# int/float(seconds) and using localtime create the time.time_struct instance.
# FILETIME(time.localtime(time.time()))

# datetime.datetime instance,
# same kind of a thing as the above 2 examples.
# FILETIME(datetime.datetime.now())

# passing anything to the constructor is almost only going to be done if you
# are going to set the file time

# properties.
# unix_epoch_seconds
#      number of seconds since the Unix Epoch
# windows_epoch_seconds
#      number of seconds since the Windows Epoch
# unix_epoch_datetime
#      datetime.datetime instance
# seconds
#      same as unix_epoch_seconds
# minutes
#      number of minutes since Unix Epoch
# hours
#      number of hours since Unix Epoch
# days
#      number of days since Unix Epoch
# int(instance)
#      same as unix_epoch_seconds
# float(instance)
#      unix_epoch_seconds with fractions of a second
# str(instance)
#      formatted string representation of the time for your locale.


class _FILETIME(ctypes.Structure):
    _fields_ = [
        ('dwLowDateTime', DWORD),
        ('dwHighDateTime', DWORD)
    ]

    def __init__(self, dwLowDateTime=None, dwHighDateTime=None):

        if dwLowDateTime is None and dwHighDateTime is None:
            super(_FILETIME, self).__init__()

        else:
            if dwHighDateTime is None:
                if isinstance(dwLowDateTime, datetime):
                    dwLowDateTime = time.mktime(datetime.now().timetuple())

                elif isinstance(dwLowDateTime, time.struct_time):
                    dwLowDateTime = time.mktime(dwLowDateTime)

                else:
                    try:
                        dwLowDateTime = dwLowDateTime.seconds
                    except AttributeError:
                        pass

                dwLowDateTime = int(dwLowDateTime)
                if (
                    (dwLowDateTime - EPOCH_AS_FILETIME) /
                    HUNDREDS_OF_NANOSECONDS < 0
                ):
                    dwLowDateTime = (
                        (dwLowDateTime * HUNDREDS_OF_NANOSECONDS) +
                        EPOCH_AS_FILETIME
                    )

                dwHighDateTime = (dwLowDateTime >> 32)
                dwLowDateTime = dwLowDateTime - ((dwLowDateTime >> 32) << 32)

            self.dwLowDateTime = DWORD(dwLowDateTime)
            self.dwHighDateTime = DWORD(dwHighDateTime)

            super(_FILETIME, self).__init__(dwLowDateTime, dwHighDateTime)

    @property
    def unix_epoch_seconds(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return (val - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS

    @property
    def windows_epoch_seconds(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return val / HUNDREDS_OF_NANOSECONDS

    @property
    def unix_epoch_datetime(self):
        return datetime.utcfromtimestamp(self.unix_epoch_seconds)

    @property
    def seconds(self):
        return self.unix_epoch_seconds

    @property
    def minutes(self):
        return int(self.seconds / 60)

    @property
    def hours(self):
        return int(self.minutes / 60)

    @property
    def days(self):
        return int(self.hours / 24)

    def __int__(self):
        return self.unix_epoch_seconds

    def __float__(self):
        val = (self.dwHighDateTime << 32) + self.dwLowDateTime
        return (val - EPOCH_AS_FILETIME) / float(HUNDREDS_OF_NANOSECONDS)

    def __str__(self):
        dt = datetime.utcfromtimestamp(self.unix_epoch_seconds)
        return dt.strftime('%c')


FILETIME = _FILETIME
PFILETIME = ctypes.POINTER(_FILETIME)


if __name__ == '__main__':

    i = time.time()
    j = (int(i) * HUNDREDS_OF_NANOSECONDS) + EPOCH_AS_FILETIME

    k_high = (j >> 32)
    k_low = j - ((j >> 32) << 32)

    l = datetime.now()
    m = time.localtime(i)

    objs = (
        ('Unix Epoch', (i,)),
        ('Win32 Epoch (64bit)', (j,)),
        ('Win32 Epock (2 * 32bit)', (k_low, k_high)),
        ('datetime.datetime', (l,)),
        ('time.struct_time', (m,))
    )

    for time_type, values in objs:

        print(time_type, '-', values)
        ft = FILETIME(*values)
        print('  windows_epoch_seconds:', ft.windows_epoch_seconds)
        print('  unix_epoch_seconds:', ft.unix_epoch_seconds)
        print('  seconds:', ft.seconds)
        print('  minutes:', ft.minutes)
        print('  hours:', ft.hours)
        print('  days:', ft.days)
        print('  __int__:', int(ft))
        print('  __float__:', float(ft))
        print('  __str__:', str(ft))
        print('  dwHighDateTime:', ft.dwHighDateTime)
        print('  dwLowDateTime:', ft.dwLowDateTime)

        print('\n\n')

Hi, sorry i dont know python but i just really need to convert my dwLowDateTime and dwHighDateTime to something readable. How do i use this script of yours?

@diogofriggo
Copy link

That was so helpful! I've been all morning looking for this. Thanks so much!

@IbrahimGawish
Copy link

That was so helpful!

@jleclanche
Copy link

Hello if you're arriving from Google. Note that I published a (public domain / CC0) python package for the same functionality as winfiletime.

https://github.com/jleclanche/winfiletime
https://pypi.org/project/winfiletime/

@BrainHurts
Copy link

Thank you, great clean code. Not only does it work but it's readable and I feel like I know what it's actually needing to do now to convert the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment