Python: strftime() UTC Offset Not working as Expected in Windows - python

Every time I use:
time.strftime("%z")
I get:
Eastern Daylight Time
However, I would like the UTC offset in the form +HHMM or -HHMM. I have even tried:
time.strftime("%Z")
Which still yields:
Eastern Daylight Time
I have read several other posts related to strftime() and %z always seems to return the UTC offset in the proper +HHMM or -HHMM format. How do I get strftime() to output in the +HHMM or -HHMM format for python 3.3?
Edit: I'm running Windows 7

In 2.x, if you look at the docs for time.strftime, they don't even mention %z. It's not guaranteed to exist at all, much less to be consistent across platforms. In fact, as footnote 1 implies, it's left up to the C strftime function. In 3.x, on the other hand, they do mention %z, and the footnote that explains that it doesn't work the way you'd expect is not easy to see; that's an open bug.
However, in 2.6+ (including all 3.x versions), datetime.strftime is guaranteed to support %z as "UTC offset in the form +HHMM or -HHMM (empty string if the the object is naive)." So, that makes for a pretty easy workaround: use datetime instead of time. Exactly how to change things depends on what exactly you're trying to do — using Python-dateutil tz then datetime.now(tz.tzlocal()).strftime('%z') is the way to get just the local timezone formatted as a GMT offset, but if you're trying to format a complete time the details will be a little different.
If you look at the source, time.strftime basically just checks the format string for valid-for-the-platform specifiers and calls the native strftime function, while datetime.strftime has a bunch of special handling for different specifiers, including %z; in particular, it will replace the %z with a formatted version of utcoffset before passing things on to strftime. The code has changed a few times since 2.7, and even been radically reorganized once, but the same difference is basically there even in the pre-3.5 trunk.

For a proper solution, see abarnert’s answer below.
You can use time.altzone which returns a negative offset in seconds. For example, I’m on CEST at the moment (UTC+2), so I get this:
>>> time.altzone
-7200
And to put it in your desired format:
>>> '{}{:0>2}{:0>2}'.format('-' if time.altzone > 0 else '+', abs(time.altzone) // 3600, abs(time.altzone // 60) % 60)
'+0200'
As abarnert mentioned in the comments, time.altzone gives the offset when DST is active while time.timezone does for when DST is not active. To figure out which to use, you can do what J.F. Sebastian suggested in his answer to a different question. So you can get the correct offset like this:
time.altzone if time.daylight and time.localtime().tm_isdst > 0 else time.timezone
As also suggested by him, you can use the following in Python 3 to get the desired format using datetime.timezone:
>>> datetime.now(timezone.utc).astimezone().strftime('%z')
'+0200'

Use time.timezone to get the time offset in seconds.
Format it using :
("-" if time.timezone > 0 else "+") + time.strftime("%H:%M", time.gmtime(abs(time.timezone)))
to convert the same to +/-HH:MM format.
BTW isn't this supposed to be a bug ? According to strftime docs.
Also I thought this SO answer might help you to convert from Zone offset string to HH:MM format. But since "%z" is not working as expected, I feel its moot.
NOTE: The time.timezone is immune to Daylight savings.

It will come as no surprise that this bug persists in, what is the latest Windows version available currently, Win 10 Version 1703 (Creators). However, time marches on and there is a lovely date-and-time library called pendulum that does what the question asks for. Sébastien Eustace (principal author of the product?) has shown me this.
>>> pendulum.now().strftime('%z')
'-0400'
pendulum assumes UTC/GMT unless told otherwise, and keeps timezone with the date-time object. There are many other possibilities, amongst them these:
>>> pendulum.now(tz='Europe/Paris').strftime('%z')
'+0200'
>>> pendulum.create(year=2016, month=11, day=5, hour=16, minute=23, tz='America/Winnipeg').strftime('%z')
'-0500'
>>> pendulum.now(tz='America/Winnipeg').strftime('%z')
'-0500'

Related

How do I convert a struct_time output into DD/MM/YY, Hour:Minute:Second format?

I'm relatively uninitiated when it comes to Python, and I'm trying to figure out how to take an output I'm getting from a sensor into proper day, month, year and hour, minute, second format.
An example of the output, which also includes a basic counter (the first output), and a timestamp (the third output) is shown below:
(305, struct_time(tm_year=2022, tm_mon=11, tm_mday=9, tm_hour=16, tm_min=42, tm_sec=8, tm_wday=2, tm_yday=313, tm_isdst=-1), 7.036)
I've seen a lot of questions and answers for this, but I'm left feeling kind of stumped on all of them because I'm not sure how to take the output I have (real_time, which gives a struct_time output) and turn it into this format. Any help (and understanding about my lack of fluency in this field) would be really appreciated!
time.strftime exists for exactly this purpose:
import time
now_local = time.localtime()
fmt = "%d/%m/%Y %H:%M:%S"
out = time.strftime(fmt, now_local)
print(out)
However, two words of warning:
time.struct_time is not "timezone aware". This will turn out to matter when you least expect it. Unless you are very sure that you know the timezone of the incoming data, and have the correct safeguards in your application and database for managing time zone iformation, use the datetime.datetime class instead.
D/M/Y date format can be ambiguous. Y-M-D format is substantially safer. It is not ambiguous in any widely-used locale, and it has the extra benefit that lexical ordering of Y-M-D strings is also a correct ordering of the dates that they represent. This format is laid out by RFC 3339 and has become widely accepted as the standard, correct formatting for datetime strings.
So as it turns out, I was able to find a solution after all. Essentially I just used this function:
def _format_datetime(datetime):
return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
datetime.tm_mon,
datetime.tm_mday,
datetime.tm_year,
datetime.tm_hour,
datetime.tm_min,
datetime.tm_sec,
)
And then applied it to the struct_time output as such (with real_time being said output):
real_time = time.localtime()
current_time = time.monotonic()
formatted_time = _format_datetime(real_time)
Hopefully this helps other people using CircuitPython for similar purposes!

What the meaning of T Z for date?

I am using api it require date as this format
2020-03-01T00:00:00Z
I googled around and couldn't under stand what the T Z means.
For Now I made this string with this code by python
dt_now.strftime('%Y-%m-%dT%H:%M:%SZ')
However it looks a bit awkward and I am not sure if it is correct.
Is there any good way for python datetime??
This looks like ISO 8601 time format. The T stands for time and is used as separator, while Z determines time offset and stands for Zulu which is commonly used, military originated, name alias for UTC+0 offset. For other offsets you need to specify it as HH:MM, with + or - respectively. So the Z is therefore equivalent of writing +00:00.
See https://en.wikipedia.org/wiki/ISO_8601 for more info.

Why does converting timezones (and to unix timestamps) behave inconsistently in Pandas?

I'm parsing and manipulating some dates and times which, for reasons of interoperability with other systems, also need to be stored as UNIX (epoch) timestamps. In doing so, I'm seeing some weird behavior from pandas' Timestamp.tz_convert(), and then in its Timestamp.strftime() behavior in casting to epoch time, that makes me doubt my understanding of what should be going on.
The times I'm working with are in the US/Eastern timezone, but of course, epoch time is UTC, so my approach had been to cast to UTC since most conversions to/from UNIX timestamps assume that a tz-naive DateTime is in UTC. Let's leave aside whether doing that conversion is absolutely necessary to get valid timestamps; here's what I'm seeing that's problematic:
1. Using Timestamp.tz_convert() to change the timezone representation of a timestamp (i.e., a universal point in time) also changes the UNIX timestamp when you convert using Timestamp.strftime().
2. The differences in those timestamps don't even correspond to the proper hour differences between US-Eastern and GMT.
Here's some basic interactive-mode python to illustrate:
>>> import pytz
>>> from pytz import timezone
>>> import pandas as pd
>>> dtest = pd.to_datetime("Sunday, July 28, 2018 10:00 AM", infer_datetime_format=True).replace(tzinfo=timezone('America/New_York')) # okay, this should uniquely represent a point in time
>>> dtest
Timestamp('2018-07-28 10:00:00-0400', tz='America/New_York') # yup, that's the time - 10AM at GMT-0400.
>>> dtest2 = dtest.tz_convert('UTC') # convert to UTC
>>> dtest2
Timestamp('2018-07-28 14:00:00+0000', tz='UTC') # yup, same point in time, just different time zone now
>>> dtest.strftime('%s') # let's convert to unix time - this looks right
'1532786400'
>>> dtest2.strftime('%s') # should be the same, but it's not. WTF?
'1532804400'
The timestamps look like they are describing things equivalently: one is 10 AM at GMT-0400, the other is 2 PM at GMT+0000, a difference of 4 hours of clock time, as expected. They're both, of course, timezone-aware. But then converting them to UNIX timestamps yields
(A) different numbers, and even worse,
(B) numbers that differ by 5 hours (18000 seconds = 5 * 60 * 60) rather than 4, so I can't even assume that strftime() is merely ignoring timezone.
I'm using https://www.epochconverter.com/ to validate any timestamps as I sanity-check this, so that's a possible point of being misled. But according to that site,
1532786400 = 2018-07-28T10:00 -0400, and
1532804400 (that last result) = 2018-07-28T15:00 -0400, or 7pm GMT, a difference of 5 hours.
There are lots of questions on the subject of casting pandas Timestamps FROM a UNIX timestamp, but very little on questions casting TO epoch time. I can think of 2 possible explanations:
(1) tz_convert() is pulling some environment variable on my system that says I'm GMT -0500 and using that in the conversion process, in spite of that being irrelevant to converting between timezone-aware timestamps, and in so doing is actually changing the underlying point in time being represented. Or:
(2) Timestamp.strftime() is bugged and either ignoring the timezone parameter of a tz-aware timestamp or doing something truly bizarre when asked for a '%s' formatting parameter.
All advice greatly appreciated.

python, time data .. does not match .. error

I tried to submit a time var with value of 2016-03-12T01:47:57+00:00 in a timestamp field, it gives me error saying to check the syntax for errors, however when I use a function to normalize the date
t = datetime.datetime.strptime(data['time'], '%Y-%m-%dT%H:%M:%SZ').strftime('%Y-%m-%d:%H:%M:%S')
I get an error like this.
time data '2016-03-12T01:47:57+00:00' does not match format '%Y-%m-%dT%H:%M:%SZ'
What's causing your problem has already been clarified by others, but please allow me to suggest my favorite solution for cases such as yours:
from dateutil import parser
parser.parse(data['time'])
More about the dateutil module here.
There are a few problems here:
The %Z (note the captial Z!) is for time zone, for example GMT. I
think you want the lower case option: %z, which is for UTC offset.
You can read here in the docs what all the options do :)
https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
You need the % symbol before each option. You cannot write %Sz, you must write %S%z. Otherwise Python is trying to match something like 2016-03-12T01:47:57z, rather than 2016-03-12T01:47:57+00:00
Unfortunately, you can't use the %z option with strptime, see this answer:
ISO to datetime object: 'z' is a bad directive
My solution:
It sounds like you don't even want to use the UTC offset. That's fine! If you can't change the way your date string is generated, perhaps this is the best option (though it's maybe a little dirty):
t = datetime.datetime.strptime(data['time'][:-6], '%Y-%m-%dT%H:%M:%S')
This will remove the UTC offset from the string.
If you can change the way your datetime string is being generated, that would be a better solution, but I realise you might not be able to do so.
I hope this helps!

What exactly does the T and Z mean in timestamp?

I have this timestamp value being return by a web service "2014-09-12T19:34:29Z"
I know that it means timezone, but what exactly does it mean?
And I am trying to mock this web service, so is there a way to generate this timestamp using strftime in python?
Sorry if this is painfully obvious, but Google was not very helpful and neither was the strftime() reference page.
I am currently using this :
x.strftime("%Y-%m-%dT%H:%M:%S%Z")
'2015-03-26T10:58:51'
The T doesn't really stand for anything. It is just the separator that the ISO 8601 combined date-time format requires. You can read it as an abbreviation for Time.
The Z stands for the Zero timezone, as it is offset by 0 from the Coordinated Universal Time (UTC).
Both characters are just static letters in the format, which is why they are not documented by the datetime.strftime() method. You could have used Q or M or Monty Python and the method would have returned them unchanged as well; the method only looks for patterns starting with % to replace those with information from the datetime object.

Categories

Resources