python convert filetime to datetime for dates before 1970 - python

I need to convert filetime to datetime. I am using this code filetime.py, from here as mentioned in this thread Datetime to filetime (Python).
In the code
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
HUNDREDS_OF_NANOSECONDS = 10000000
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)
"""
# Get seconds and remainder in terms of Unix epoch
(s, ns100) = divmod(ft - EPOCH_AS_FILETIME, HUNDREDS_OF_NANOSECONDS)
# Convert to datetime object
dt = datetime.utcfromtimestamp(s)
# Add remainder in as microseconds. Python 3.2 requires an integer
dt = dt.replace(microsecond=(ns100 // 10))
return dt
datetime.utcfromtimestamp does not take negative value on windows system, so I can't convert filetime before Jan 1st 1970. But I can convert dates before 1970 on Mac using the exact same code (reason here). Is there any workaround for windows?

By adding a timedelta to a reference date you can use any date formula you'd like. timedelta is allowed to be positive or negative.
def filetime_to_dt(ft):
us = (ft - EPOCH_AS_FILETIME) // 10
return datetime(1970, 1, 1) + timedelta(microseconds = us)

According to docs, you have to use:
dt = datetime.fromtimestamp(s, datetime.timezone.utc)
instead of:
dt = datetime.utcfromtimestamp(s)

first you need to convert it to a recognizable filetime format like this:
>>> dwLowDateTime = 0x0F7297A80
>>> dwHighDateTime = 0x1C3F10F << 32
>>> ft = (dwLowDateTime & 0xFFFFFFFF) | dwHighDateTime
127210265370000000
and then use this script, it converts filetime to datetime and vice versa https://gist.github.com/Mostafa-Hamdy-Elgiar/9714475f1b3bc224ea063af81566d873
>>> filetime_to_dt(ft)
2004-02-12 02:28:57

Use timedeltas to add/subtract/divide between time frames:
FILE_TIME_EPOCH = datetime.datetime(1601, 1, 1)
FILE_TIME_MICROSECOND = 10 # FILETIME counts 100 nanoseconds intervals = 0.1 microseconds, so 10 of those are 1 microsecond
def convert_from_file_time(file_time):
microseconds_since_file_time_epoch = file_time // FILE_TIME_MICROSECOND
return FILE_TIME_EPOCH + datetime.timedelta(microseconds=microseconds_since_file_time_epoch)
And the other side of this is:
def convert_to_file_time(date_time):
microseconds_since_file_time_epoch = (date_time - FILE_TIME_EPOCH) // datetime.timedelta(microseconds=1)
return microseconds_since_file_time_epoch * FILE_TIME_MICROSECOND

Related

how to convert datetime-like string into milliseconds

I have a user-defined function (return_times) that takes json file and returns two datetime-like strings.
time_1, time_2= return_times("file.json")
print(time_1, time_2) # outputs: 00:00:11.352 00:01:51.936
By datetime-like string I mean 00:00:11.352 which suits '%H:%M:%S.%f' formatting. However, when I try to convert them into milliseconds, I get negative values.
from datetime import datetime
dt_obj_1 = datetime.strptime(time_1, '%H:%M:%S.%f')
start_ms = dt_obj_1.timestamp() * 1000
dt_obj_2 = datetime.strptime(time_2, '%H:%M:%S.%f')
end_ms = dt_obj_2.timestamp() * 1000
print(start_ms, end_ms ) # outputs: -2209019260648.0 -2209019160064.0
If I success I would like to trim a video with the following command:
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
ffmpeg_extract_subclip("long_video.mp4", start_ms, end_ms, targetname="video_trimmed.mp4"), so just delete ` * 1000` part.
Note that ffmpeg_extract_subclip requires its t1 and t2 parameters to be in seconds, not in milliseconds as I initially thought.
Because of those negative integers I am not able to successfully run the trimming process.
I searched the web that mainly discusses several formats for the year, month and day, but not '%H:%M:%S.%f'.
What may I be overlooking?
What may I be overlooking?
time.strptime docs
The default values used to fill in any missing data when more accurate
values cannot be inferred are (1900, 1, 1, 0, 0, 0, 0, 1, -1).
whilst start of epoch is 1970. You might get what you want by computing delta between what you parsed and default strptime as follows:
import datetime
time1 = "00:00:11.352"
delta = datetime.datetime.strptime(time1, "%H:%M:%S.%f") - datetime.datetime.strptime("", "")
time_s = delta.total_seconds()
print(time_s)
output
11.352
You need to add the year date (year, month, day) to datetime, else this will default to 1 January 1900.
What you do is this:
from datetime import datetime
s = "00:00:11.352"
f = '%H:%M:%S.%f'
datetime.strptime(s, f) # datetime.datetime(1900, 1, 1, 0, 0, 11, 352000)
One way to do this is to append the date-string to the time-string you receive from return_times
From https://stackoverflow.com/a/59200108/2681662
The year 1900 was before the beginning of the UNIX epoch, which
was in 1970, so the number of seconds returned by timestamp must be
negative.
What to do?
It's better to use a time object instead of a datetime object.
from datetime import time
time_1 = "00:00:11.352"
hours, minutes, seconds = time_1.split(":")
print(time(hour=int(hours), minute=int(minutes), second=int(float(seconds)),
microsecond=int(float(seconds) % 1 * 1000000)))
You can split the time string into hours, minutes, seconds and miliseconds and with some simple math calculations, you get the whole time in miliseconds

find the interval of a given date in python

I'm struggling with date objects in python.
I have the following data:
from datetime import datetime, timedelta
# date retrieved from a list
ini = [u'2016-01-01']
# transform the ini in a readable string
ini2 = ', '.join(map(str, ini))
# transform the string a date object
date_1 = datetime.strptime(ini2, "%Y-%m-%d")
# number that is the length of the date
l = 365.0
# adding l to ini2
final = date_1 + timedelta(days = l)
Now I'd need to split the whole interval (that is the period from date_1 to final) by an input number (e.g. ts = 4) and, given another input date (e.g. new_date = u'2016-05-19') check in which interval it is (in the example 19th of May is in t2 = 2).
I hope I made myself clear enough.
Thanks
I tried different approaches but none seems the right one.
This might help:
from datetime import datetime, timedelta
def which_interval(date0, delta, date1, n_intervals):
date0 = datetime.strptime(date0, '%Y-%m-%d')
delta = timedelta(days = delta)
date1 = datetime.strptime(date1, '%Y-%m-%d')
delta1 = date1 - date0
quadrile = int(((float(delta1.days) / delta.days) * n_intervals))
return quadrile
# Example: figure out which quarter August 1st is in
interval = which_interval(
'2016-01-01',
366,
'2016-08-01',
4)
print '2016-08-01 is in interval %d, Q%d'%(interval, interval+1)
Note that this function uses python indices so it will start at quarter 0 and end at quarter 3. If you want 1-based indices (so the answer will be 1, 2, 3, or 4) you would want to add 1 to the result.
the timedelta object supports division, so use floor division by a step and you will get an interval in range(ts)
new_date = datetime.strptime(u'2016-05-19', "%Y-%m-%d")
ts = 4
step = timedelta(days=l)/ts #divide by the number of steps
interval = (new_date - date_1)//step #get the number this interval is in
so for date_1 <= new_date < date_1 + step interval will be 0, for date_1+step<=new_date < date_1 + step*2 interval will be 1, etc.
This of course is using python style indices so to get the number starting from 1, add one:
interval = (new_date - date_1)//step + 1
EDIT: the functionality to divide timedelta objects was only added in python3, you would need to use the .total_seconds() method to do the calculation in python 2:
step = timedelta(days=l).total_seconds()/ts #divide by inteval
interval = (new_date - date_1).total_seconds()//step
You could calculate this using the seconds total of the intervals.
import math
from datetime import datetime, timedelta
l = 365.0
factor = 4
date_1 = datetime.strptime('2016-01-01', "%Y-%m-%d")
lookup_dt = datetime.strptime('2016-12-01', "%Y-%m-%d")
def get_interval_num(factor, start_dt, td, lookup_dt):
final = start_dt + td
interval = (final - start_dt).total_seconds()
subinterval = interval / factor
interval_2 = (lookup_dt - start_dt).total_seconds()
return int(math.ceil(interval_2 / subinterval))
num = get_interval_num(
factor=factor,
start_dt=date_1,
td= timedelta(days=l),
lookup_dt=lookup_dt
)
print("The interval number is: %s" % num)
Output would be:
The interval number is: 4
EDIT: clearified variable naming, extended code snippet

Convert TLE times (decimal days) to seconds after epoch

The standard two line element (TLE) format contains times as 2-digit year plus decimal days, so 16012.375 would be January 12, 2016 at 09:00. Using python's time or datatime modules, how can I convert this to seconds after epoch? I think I should use structured time but I am not sure how. seconds_of is a fictitious function - need to replace with something real.
EDIT: It will be most helpful if the answer is long (verbose) - like one step per line or so, so I can understand what is happening.
EDIT 2: After seeing the comments from #J.F.Sebastian I looked at the link for TLE and found it nowhere states "UTC". So I should point out the initial information and final information are UTC. There is no reference to local time, time zone, or system time.
e.g.
tim = "16012.375"
year = 2000 + int(tim[0:2])
decimal_days = float(tim[2:])
print year, decimal_days
2016, 12.375
# seconds_of is a fictitious function - need to replace with something real
seconds_after_epoch = seconds_of(2016,1,1) + (3600. * 24.) * decimal_days
You could try something like this [EDIT according to the comments].
import datetime
import time
# get year 2 digit and floating seconds days
y_d, nbs = "16012.375".split('.')
# parse to datetime (since midnight and add the seconds) %j Day of the year as a zero-padded decimal number.
d = datetime.datetime.strptime(y_d, "%y%j") + datetime.timedelta(seconds=float("." + nbs) * 24 * 60 * 60)
# 1.0 => 1 day
# from time tuple get epoch time.
time.mktime(d.timetuple())
#1481896800.0
It is easy to get datetime object given year and decimal_days:
>>> from datetime import datetime, timedelta
>>> year = 2016
>>> decimal_days = 12.375
>>> datetime(year, 1, 1) + timedelta(decimal_days - 1)
datetime.datetime(2016, 1, 12, 9, 0)
How to convert the datetime object into "seconds since epoch" depends on the timezone (local, utc, etc). See Converting datetime.date to UTC timestamp in Python e.g., if your input is in UTC then it is simple to get "seconds since the Epoch":
>>> utc_time = datetime(2016, 1, 12, 9, 0)
>>> (utc_time - datetime(1970, 1, 1)).total_seconds()
1452589200.0

How to convert a Unix timestamp to DateTime and vice versa with python?

A unix timestamp is an int which gives the number of seconds since January 1, 1970, UTC.
Is there a way to convert the .NET timestamp to unix timestamp using python ? or can this only be done in C# ?
Any help would be greatly appreciated.
Similar question: How to convert a Unix timestamp to DateTime and vice versa? this contains how to do this in C I am looking for a way to do this in python 34
Is there a way to convert the .NET timestamp to unix timestamp using python?
posix_epoch_as_dotnet = 621355968000000000
# convert .NET timestamp to POSIX timestamp
posix_timestamp = (130900894153614080 - posix_epoch_as_dotnet) // 10**7
It is easy to convert between a datetime object that represents time in UTC and the timestamps:
#!/usr/bin/env python
from datetime import datetime, timedelta
dotnet_epoch = datetime(1, 1, 1)
posix_epoch = datetime(1970, 1, 1)
utc_time = dotnet_epoch + timedelta(microseconds=dotnet_timestamp//10)
utc_time = posix_epoch + timedelta(seconds=posix_timestamp)
and back:
posix_timestamp = (utc_time - posix_epoch) // timedelta(seconds=1)
dotnet_timestamp = 10 * (utc_time - dotnet_epoch) // timedelta(microseconds=1)
See totimestamp() function on how to implement // timedelta() on older Python versions.

Convert fractional years to a real date in Python

How do I convert fractional years to a real date by using Python?
E. g. I have an array
[2012.343, 2012.444, 2012.509]
containing fractional years and I would like to get "yyyy-mm-dd hh:mm".
Here it`s a better solution, that give you the answer in datetime format.
from datetime import timedelta, datetime
def convert_partial_year(number):
year = int(number)
d = timedelta(days=(number - year)*365)
day_one = datetime(year,1,1)
date = d + day_one
return date
This solution doesnt count the extra day in leap years. If you need to do so, make a function is_leap(year) that returns a bool, and change my code to this:
from datetime import timedelta, datetime
def convert_partial_year(number):
year = int(number)
d = timedelta(days=(number - year)*(365 + is_leap(year)))
day_one = datetime(year,1,1)
date = d + day_one
return date
Check out datetime module. You can find a even better solution for your problem there.
import datetime as DT
def t2dt(atime):
"""
Convert atime (a float) to DT.datetime
This is the inverse of dt2t.
assert dt2t(t2dt(atime)) == atime
"""
year = int(atime)
remainder = atime - year
boy = DT.datetime(year, 1, 1)
eoy = DT.datetime(year + 1, 1, 1)
seconds = remainder * (eoy - boy).total_seconds()
return boy + DT.timedelta(seconds=seconds)
def dt2t(adatetime):
"""
Convert adatetime into a float. The integer part of the float should
represent the year.
Order should be preserved. If adate<bdate, then d2t(adate)<d2t(bdate)
time distances should be preserved: If bdate-adate=ddate-cdate then
dt2t(bdate)-dt2t(adate) = dt2t(ddate)-dt2t(cdate)
"""
year = adatetime.year
boy = DT.datetime(year, 1, 1)
eoy = DT.datetime(year + 1, 1, 1)
return year + ((adatetime - boy).total_seconds() / ((eoy - boy).total_seconds()))
You can determine the epoch time of Jan 1 of the year part. Add that to the fractional part times 365 * 24 * 60 * 60. Then convert your epoch time to a date time.
see Python: Converting Epoch time into the datetime

Categories