django, python why timestamp changes after localize - python

CODE:
import pytz
from django.utils import timezone
KST = pytz.timezone('Asia/Seoul')
UTC = pytz.timezone('UTC')
default_time = timezone.datetime(2021, 11, 29, 16, 44)
current_manual_kst = KST.localize(default_time)
current_manual_utc = default_time
print(current_manual_kst.timestamp())
print(current_manual_utc.timestamp())
RESULT:
>>> 1638171840.0
>>> 1638204240.0
So, I can see that results are different.
I thought timestamps should be the same but results are not.
Why this happened?
And How to get the same timestamps (by default: UTC) from KST.localized datetime?

A timestamp is expressed in UNIX time, which is the number of seconds since midnight January 1st 1970 UTC. In order to convert a datetime to such a UNIX timestamp, that datetime needs to be interpreted as some timezone. Because you can't express it relative to 1970 UTC without defining what timezone it's in. So if you have a naïve datetime object (without timezone) and take its timestamp(), it is interpreted as being in your local timezone and is converted to UTC from there.
And 16:44 in Seoul is apparently a different time than 16:44 in your computer's "local" timezone.

Related

How to convert string datetime to UTC UNIX?

I have date in the as string in the following format: 202001010000
I am trying to convert this to UNIX format and get the result in UTC
I did:
import datetime
stime = "202001010000"
print(int(datetime.datetime.strptime(stime, "%Y%m%d%H%M").replace(tzinfo=datetime.timezone.utc).timestamp()))
and this is giving me the output in UNIX, but in CEST format.
With the above code I get: 1577836800 but I want the output to be 1577833200
What is the mistake I am doing?
You're setting time zone to UTC when converting to datetime. But since your input represents time in Germany you want a time zone that is active there. EX:
from datetime import datetime
from zoneinfo import ZoneInfo # Python 3.9+, can use backports.zoneinfo for older versions
stime = "202001010000"
# stime represents time in Germany so we use time zone
time_zone = ZoneInfo('Europe/Berlin')
# to datetime, with tz set:
dtobj = datetime.strptime(stime, "%Y%m%d%H%M").replace(tzinfo=time_zone)
# unix time
ts = dtobj.timestamp()
print(ts)
# 1577833200.0
# back to datetime, again specify time zone
dtobj = datetime.fromtimestamp(ts, tz=time_zone)
print(dtobj)
# 2020-01-01 00:00:00+01:00
Note that if the input represents the same time zone your OS is configured to use, this works correctly without setting a time zone. But I think it's better to be explicit here, to avoid confusion if you e.g. run this script on a machine configured to use another time zone.
What you're trying to get is 7 hours behind and you cannot do that from your start date. You must push your start date back 1 day and push your hours forward 17. This code will work for you
import datetime
stime = "201912310000"
my_date = datetime.datetime.strptime(stime, "%Y%m%d%H%M")
my_date_utc = my_date.replace(hour=17)
my_timestamp = my_date_utc.timestamp()
print(int(my_timestamp))

How to get current datetime in this format 2020-01-13T09:25:19-0330 in Python?

What is this date format 2020-01-13T09:25:19-0330 ? and how can I get the current datetime in this format in python ?
Edited: Also note there are only 4 digits after last -. The API which I need to hit accepts exactly this format.
2nd Edit: Confirmed from api's dev team, last 4 digits are milliseconds, with 0 prepended. ex, 330 is the milliseconds, and they mention it as 0330.
It's an ISO 8601 timestamp format.
In order to get the current time in that format:
from datetime import datetime
print(datetime.now().isoformat())
In your case, the iso format is truncated to seconds, and has a timezone:
from datetime import datetime, timezone, timedelta
tz = timezone(timedelta(hours=-3.5))
current_time = datetime.now(tz)
print(current_time.isoformat(timespec="seconds"))
Where -3.5 is the UTC offset.
If you wish to use the system's local timezone, you can do so like this:
from datetime import datetime, timezone, timedelta
current_time = datetime.now().astimezone()
print(current_time.isoformat(timespec="seconds"))

Converting to a non-daylight savings timezone

In python, I am trying to convert a bunch of UTC datetimes into a localized timezone but STANDARD time year round. For example, for pacific time, I need PST year round, not PDT and PST switching from summer to winter. Or to rephrase my question, is there a way to specify 'Standard' time for a timezone?
You can specify the UTC offset for a specific time zone that does not change with daylight savings. Following example converts UTC to Pacific Standard Time (PST).
from datetime import datetime, timedelta, timezone
utc = datetime(2019, 8, 7, 10, 30, tzinfo=timezone.utc)
pst = utc.astimezone(timezone(-timedelta(hours=8)))
print(utc)
# 2019-08-07 10:30:00+00:00
print(pst)
# 2019-08-07 02:30:00-08:00
To obtain the number of hours of offset for a named time zone:
import pytz
def get_standard_time_offset(tz_name):
t = pytz.timezone(tz_name)
# DATE HERE IS AN ARBITRARY WINTER DATE THAT WOULDN'T WORK IN THE SOUTHERN HEMISPHERE
offset = t.utcoffset(datetime(2010,1,1))
hrsoffset = offset.total_seconds()/3600
return hrsoffset
from datetime import datetime, timezone
utc_dt = "enter here UTC time "
utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)

Python datetime.datetime from time.structtime difference

I use feedparser to grab the entries from some RSS feeds.
The entries have a published_parsed field which are parsed by feedparser into time.structtime.
I use this function to convert the time.structtime into a datetime.datetime:
def publishParsedToDatetime(structTime):
return datetime.datetime.fromtimestamp(time.mktime(structTime))
Input (structtime):
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=1, tm_hour=20, tm_min=28, tm_sec=33, tm_wday=5, tm_yday=213, tm_isdst=0)
Output (datetime):
2015-08-01 21:28:33
I see a problem which could be timezone related, there is 1 hour difference between the structtime and the datetime values.
The structtime value is UTC.
But the datetime.datetime value is neither UTC, nor my current timezone (CET, Central European Time, we observe Summertime, so we have UTC + 2hrs at the moment).
How can this be explained?
Actually, as explained in the documentation for datetime.fromtimestamp, it converts to local time by default:
Return the local date and time corresponding to the POSIX timestamp, such as is returned by time.time(). If optional argument tz is None or not specified, the timestamp is converted to the platform’s local date and time, and the returned datetime object is naive
The 1 hour difference can then be explained by the field tm_isdst=0 tells it to not use daylight savings (despite your local time zone using it).
To see this more clearly, we construct two test cases
import time, datetime
# this is how your time object was constructed before
tm_isdst = 0
t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
print("Old conversion: {0}".format(datetime.datetime.fromtimestamp(t)))
# this is what happens if you let mktime "divine" a time zone
tm_isdst = -1
t = time.mktime((2015, 8, 1, 20, 28, 33, 5, 213, tm_isdst))
print("New conversion: {0}".format(datetime.datetime.fromtimestamp(t)))
The output of this is as follows:
Old conversion: 2015-08-01 21:28:33
New conversion: 2015-08-01 20:28:33
The problem then, you see, is that the structTime object being passed to your publishParsedToDatetime has tm_isdst=0 but the time stamp you wanted to parse was for a DST time zone.
As you have already noted in another comment, the proper solution to this is probably to always use UTC in your back-end code, and only do time zone handling when showing the time to the user, or when reading user input.
calendar.timegm takes a UTC timetuple as input and returns its timestamp.
In contrast, time.mktime takes a local timetuple as input and returns its (UTC) timestamp. All timestamps represent seconds since the Epoch, 1970-1-1 00:00:00 UTC.
utcfromtimestamp takes a timestamp as input and converts it to a naive
(i.e. timezone-unaware) UTC datetime.
fromtimestamp takes the same timestamp and converts it to the corresponding
naive local datetime.
Since your timetuples (e.g. structTime) are UTC timetuples, you should use calendar.timegm, not time.mktime, to find the correct timestamp.
Once you have the correct timestamp, fromtimestamp will return the corresponding naive local datetime.
import time
import calendar
import datetime as DT
timetuple = (2015, 8, 1, 20, 28, 33, 5, 213, 0)
timestamp = calendar.timegm(timetuple)
naive_local_date = DT.datetime.fromtimestamp(timestamp)
print('Naive local: {}'.format(naive_local_date))
yields
Naive local: 2015-08-01 22:28:33

Convert to UTC Timestamp

# parses some string into that format.
datetime1 = datetime.strptime(somestring, "%Y-%m-%dT%H:%M:%S")
# gets the seconds from the above date.
timestamp1 = time.mktime(datetime1.timetuple())
# adds milliseconds to the above seconds.
timeInMillis = int(timestamp1) * 1000
How do I (at any point in that code) turn the date into UTC format? I've been ploughing through the API for what seems like a century and cannot find anything that I can get working. Can anyone help? It's currently turning it into Eastern time i believe (however I'm in GMT but want UTC).
EDIT: I gave the answer to the guy with the closest to what I finally found out.
datetime1 = datetime.strptime(somestring, someformat)
timeInSeconds = calendar.timegm(datetime1.utctimetuple())
timeInMillis = timeInSeconds * 1000
:)
datetime.utcfromtimestamp is probably what you're looking for:
>>> timestamp1 = time.mktime(datetime.now().timetuple())
>>> timestamp1
1256049553.0
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2009, 10, 20, 14, 39, 13)
I think you can use the utcoffset() method:
utc_time = datetime1 - datetime1.utcoffset()
The docs give an example of this using the astimezone() method here.
Additionally, if you're going to be dealing with timezones, you might want to look into the PyTZ library which has lots of helpful tools for converting datetime's into various timezones (including between EST and UTC)
With PyTZ:
from datetime import datetime
import pytz
utc = pytz.utc
eastern = pytz.timezone('US/Eastern')
# Using datetime1 from the question
datetime1 = datetime.strptime(somestring, "%Y-%m-%dT%H:%M:%S")
# First, tell Python what timezone that string was in (you said Eastern)
eastern_time = eastern.localize(datetime1)
# Then convert it from Eastern to UTC
utc_time = eastern_time.astimezone(utc)
def getDateAndTime(seconds=None):
"""
Converts seconds since the Epoch to a time tuple expressing UTC.
When 'seconds' is not passed in, convert the current time instead.
:Parameters:
- `seconds`: time in seconds from the epoch.
:Return:
Time in UTC format.
"""
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))`
This converts local time to UTC
time.mktime(time.localtime(calendar.timegm(utc_time)))
http://feihonghsu.blogspot.com/2008/02/converting-from-local-time-to-utc.html
If converting a struct_time to seconds-since-the-epoch is done using mktime, this
conversion is in local timezone. There's no way to tell it to use any specific timezone, not even just UTC. The standard 'time' package always assumes that a time is in your local timezone.
You probably want one of these two:
import time
import datetime
from email.Utils import formatdate
rightnow = time.time()
utc = datetime.datetime.utcfromtimestamp(rightnow)
print utc
print formatdate(rightnow)
The two outputs look like this
2009-10-20 14:46:52.725000
Tue, 20 Oct 2009 14:46:52 -0000

Categories

Resources