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

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!

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!

Pandas: Change object to Date_time

I'm learning Pandas and I have a problem trying to change a format from Object to Date_time.
When I use 'to_datetime' the date I get in return is like in ISO Format, and I just want DD/MM/YYYY (13/10/1960). And I doing something wrong? Thanks a lot!!
enter image description here
At a glance, it doesn't seem like the code uses the right format.
The to_datetime() with the format argument follows strftime standards per the documentation here, and it's a way to tell the method how the original time was represented (so it can properly format it into a datetime object). An example can be seen from this Stack Overflow question.
Simple example:
datetime_object = pd.to_datetime(format='%d/%m/%Y')
The next problem is how you want that datetime object to be printed out (i.e. DD/MM/YYYY). Just throwing thoughts out there (would comment, but I don't have those privileges yet), if you want to print the string, you can cast that datetime object into the string that you want. Many ways to do this, one of which is to use strftime().
Simple example:
date_as_string = datetime_object.strftime('%d/%m/%Y')
But of course, why would you use a datetime object in that case. So the other option I can think of is to override how the datetime object is printed (redefining __str__ in a new class of datetime).

Parsing date which may or may not contain milliseconds

So this question is more of best way to handle this sort of input in python. Here is an example of input date 2018-12-31 23:59:59.999999. The millisecond part may or may not be part of input.
I am currently using this code to convert this to datetime
input_ts = datetime.datetime.strptime(input_str, '%Y-%m-%dT%H:%M:%S.%f')
But the problem in this case is that it will throw an exception if input string doesn't contain milliseconds part i.e., 2018-12-31 23:59:59
In Java, I could have approached this problem in two ways. (its a pseudo explanation, without taking into account of small boundary checks)
(preferred approach). Check the input string length. if its less than 19 then it is missing milliseconds. Append .000000 to it.
(not preferred). Let the main code parse the string, if it throws an exception, then parse it with new time format i.e., %Y-%m-%dT%H:%M:%S
The third approach could be just strip off milliseconds.
I am not sure if python has anything built-in to handle these kind of situations. Any suggestions?
You could use python-dateutil library, it is smart enough to parse most of the basic date formats.
import dateutil.parser
dateutil.parser.parse('2018-12-31 23:59:59.999999')
dateutil.parser.parse('2018-12-31 23:59:59')
In case you don't want to install any external libraries, you could iterate over list of different formats as proposed in this answer.
from datetime import datetime # import datetime class from datetime package
dt = datetime.now() # get current time
dt1 = dt1.strftime('%Y-%m-%d %H:%M:%S') # converting time to string
dt3 = dt2.strptime('2018/5/20','%Y/%m/%d') # converting a string to specified time

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

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'

Elegantly generating a datetime from a URL in Django?

I'm working on a web app that will allow the user to do a lookup by date, so that, for example:
results = Something.objects.filter(end = date)
I'm planning on passing in the date information via the URL, like this:
example.com/invoicer?2/9/1984
I'll then grab the date via request.GET, break off the first part and store it as the month, delete the slash, break off the second part as the date, etc. etc.
I'm not too worried about error/input checking, since only trusted administrators will have access to this, but it seems like a crappy way of going about generating the datetime.
Any better ideas?
[...] break off the first part and store it as the month, delete the slash, break off the second part as the date, etc. etc.
That's indeed is not an ideal way to generate the datetime. You're better off with string parsing:
>>> datetime.datetime.strptime('2/9/1984', '%m/%d/%Y')
datetime.datetime(1984, 2, 9, 0, 0)
You'll have an easier time if you use a parameter for the value:
invoicer?date=2/9/1984
and you might prefer to use an ISO8601 date:
invoicer?date=19840209
I'm not sure what your user interface to this is, or are you expecting people to type these URLs by hand? If not, IS08601 is the way to go.
Seems pretty normal. One other way we do it is not to use the query string but the path:
example.com/invoicer/end_date/1984-02-09
you can convert to a unix/epoch date and pass as a long integer.
super simple and no worrying about string parsing. just use python's time.gmtime to get your time from the number of seconds.
example.com/invoicer?date=1280139973
time.gmtime(1280139973)

Categories

Resources