make python datetime include local time zone - python

I wrote this python code but I am facing problems to make it work properly at the level of time zone. So basically the datetime.now() is not working as expected as it is not compliant to my local time (Paris local time) . Any idea how to sovle this please.
from datetime import datetime, timedelta
from airflow.operators import
GoogleCloudStorageToGoogleCloudStorageOperator
copy_trm = GoogleCloudStorageToGoogleCloudStorageOperator(
task_id='copy_file',
source_bucket="source",
source_object="input-files/*.orc",
destination_bucket="destination",
destination_object="output-files/recent",
last_modified_time=datetime.now() - timedelta(days=1)
Best Regards

use pytz module
import pytz
tz = pytz.timezone('Pacific/Johnston') #change it to your suitable timezone
ct = datetime.now(tz=tz)

If you want to know your current timezone name. It is possible with below code:
import datetime
dt = datetime.datetime.now()
dt.astimezone().tzname()
Output:
'IST'
You can send time in UTC format as:
dt.astimezone().utcnow()

With the standard library, requires the numerical offset
If you have the numerical offset of your timezone (compared to UTC) then you use the standard library:
>>> from datetime import datetime, timezone
>>> datetime.now().strftime("%c (%Z)")
'Wed Feb 13 23:00:06 2019 ()'
>>> datetime.now(tz=timezone.utc).strftime("%c (%Z)")
'Wed Feb 13 22:00:11 2019 (UTC)'
>>> datetime.now(tz=timezone(timedelta(hours=2))).strftime("%c (%Z)")
'Thu Feb 14 00:00:20 2019 (UTC+02:00)'
Though since the offset can change throughout the year (e.g. with daylight saving time), it is recommended to use a named timezone.
With dateutils, using the host timezones database
The Python documentation on timezone points to the dateutil.tz package which will use the timezone database from the machine it runs on. The pytz package on the other hand comes with a bundled timezone database.
I would personally recommend the dateutil package since the database already exists on the running machine. As long as the machine is kept up-to-date (as any server and PC should) you are good to go.
>>> from dateutil.tz import gettz # GNU/Linux and macOS
>>> # Or, on Windows: from dateutil.tz.win import gettz
>>> datetime.now(tz=gettz("Europe/Paris")).strftime("%c (%Z)")
'Wed Feb 13 23:00:58 2019 (CET)'
>>> datetime.now(tz=gettz("Asia/Taipei")).strftime("%c (%Z)")
'Thu Feb 14 06:01:27 2019 (CST)'

Related

Python make datetime offset aware

I want to get the offset for datetime and make an aware string.
The following IDLE code works:
Python 3.6.5 (default, Apr 1 2018, 05:46:30)
[GCC 7.3.0] on linux
import datetime
date_now = datetime.datetime.now()
date_now_with_offset = date_now.astimezone()
print(date_now_with_offset)
2018-06-03 17:48:50.258504-05:00
The following code in a script gives an error:
import datetime
date_now = datetime.datetime.now()
date_now_with_offset = date_now.astimezone()
print(date_now_with_offset)
TypeError: Required argument 'tz' (pos 1) not found
I realize that offset and timezone are different but at any given moment
the local time should be offset the same as an accurate timezone offset even though timezone offset may fluctuate during the year.
What is happening and why? What is the best solution?
If a datetime object is missing a timezone you can add it with:
from datetime import datetime, timezone
datetime(1970,1,1).replace(tzinfo=timezone.utc)
or when constructing the datetime object
datetime(1970,1,1).tzinfo==None
# Out: True
datetime(1970,1,1, tzinfo=timezone.utc).tzinfo
# Out: datetime.timezone.utc
timezone is available from version 3.2
I had a similar error with Python 3 when trying to compute the time difference
d = "Tue 01 May 2018 10:34:15 -0000" # date string with timezone
dt = datetime.strptime(d, "%a %d %b %Y %H:%M:%S %z")
dt
# datetime.datetime(2018, 5, 1, 10, 34, 15, tzinfo=datetime.timezone.utc)
dt - datetime(1970,1,1)
# TypeError: can't subtract offset-naive and offset-aware datetimes
Solution: add timezone when creating datetime or modify existing datetime object
dt.tzinfo
# datetime.timezone.utc
dt - datetime(1970,1,1, tzinfo=timezone.utc)
# datetime.timedelta(days=17652, seconds=38055)
# or modify already existing datetime
d_aware = datetime(1970,1,1).replace(tzinfo=timezone.utc)
dt - d_aware
datetime.timedelta(days=17652, seconds=38055)
Define the timezone in your date as needed/according to your knowledge of the missing timezone.
Just a note: datetime(1970,1,1, tzinfo=timezone.utc) is the Epoch time (or POSIX/Unix time) and by definition has UTC timezone.
The script is being executed by the python2 interpreter. Add an explicit python3 shebang to the script:
#! /usr/bin/env python3
import datetime
....
From your traceback: TypeError: Required argument 'tz' (pos 1) not found. Your script is using Python2, which is generally not compatible with Python3. In Python2 you have to provide a timezone. See the difference between the Python2 and Python3 documentation.
In Linux, the python word specifically means python2. Python3 is typed using python3 unless you use an alias. To fix it, change all occurrences of python to python3, as in
#! /usr/bin/env python3
python3 offset.py
Note:
From the Python3 Documentation, it does not work on all versions of Python3:
Changed in version 3.3: tz now can be omitted.
Changed in version 3.6: The astimezone() method can now be called on naive instances that are presumed to represent system local time.`
Overview: you can convert local time to another time zone and display the new time by using astimezone. The astimezone will convert the local time to the timezone datetime. timezone.utc has 0 timezone offset. astimezone changes the clock and the utc offset. astimezone moves the hours and days to match the timezone.
from datetime import datetime, timedelta, timezone
print("Eastern Standard Time Zone")
ET=timezone(timedelta(hours=-5))
dt=datetime(2017,12,30,15,9,3)
print(dt.astimezone(ET))
print("India Standard Time Zone")
IST= timezone(timedelta(hours=5,minutes=30))
dt=datetime(2017,12,30,15,9,3)
print(dt.astimezone(IST))

Today's and tomorrow's date in YYYY-MM-DD format in PST timezone in python

I need to get the date for today and tomorrow in YYYY-MM-DD format in python in PST timezone. The datetime() returns date in UTC. I have an internal JIRA system which uses PST date setting and i want to query that. The code will run in a restricted environment where i can't install any external python modules like the pytz library. I tried in a lot of ways but am unsuccessful.
Is there anyway it can be done in python?
There is confusion about the timezone for datetime.date.today(), http://docs.python.org/2/library/datetime.html It gives local time. Right now it is the 20th in Greenwich, Google:
1:55 AM
Thursday, March 20, 2014 (GMT)
Time in Greenwich, London, UK
In Colorado today() gives the 19th:
>>> import datetime
>>> str(datetime.date.today())
'2014-03-19'
>>> str(datetime.date.today() + datetime.timedelta(1))
'2014-03-20'
>>>
Seems like you can use timedelta for converting UTC to PST and todays date to tomorrows date:
from datetime import datetime, timedelta
print datetime.utcnow() - timedelta(hours=8) //convert to PST
print datetime.utcnow() + timedelta(days=1) //get tomorrow
For ‘YYYY-MM-DD’ format, there is a date.isoformat() method in python docs
I used the below code to get today's date and tomorrow's date in PST.
from datetime import datetime, timedelta
from pytz import timezone
import pytz
/*Timezone aware object*/
utc_now = pytz.utc.localize(datetime.utcnow())
pst_now = utc_now.astimezone(pytz.timezone("America/Los_Angeles"))
file_dt=pst_now.strftime("%Y-%m-%d")
print(file_dt)
curr_time=datetime.utcnow().astimezone(pytz.timezone("America/Los_Angeles")
tom_time=utc_now+datetime.timedelta(days=1)
today=curr_time.strftime("%Y-%m-%d")
tomorrow=tom_time.strftime("%Y-%m-%d")
print("Today is "+today+" and Tomorrow is "+tomorrow)

Using dateutil.parser to parse a date in another language

Dateutil is a great tool for parsing dates in string format. for example
from dateutil.parser import parse
parse("Tue, 01 Oct 2013 14:26:00 -0300")
returns
datetime.datetime(2013, 10, 1, 14, 26, tzinfo=tzoffset(None, -10800))
however,
parse("Ter, 01 Out 2013 14:26:00 -0300") # In portuguese
yields this error:
ValueError: unknown string format
Does anybody know how to make dateutil aware of the locale?
As far as I can see, dateutil is not locale aware (yet!).
I can think of three alternative suggestions:
The day and month names are hardcoded in dateutil.parser (as part of the parserinfo class). You could subclass parserinfo, and replace these names with the appropriate names for Portuguese.
Modify dateutil to get day and month names based on the user’s locale. So you could do something like
import locale
locale.setlocale(locale.LC_ALL, "pt_PT")
from dateutil.parser import parse
parse("Ter, 01 Out 2013 14:26:00 -0300")
I’ve started a fork which gets the names from the calendar module (which is locale-aware) to work on this: https://github.com/alexwlchan/dateutil
Right now it works for Portuguese (or seems to), but I want to think about it a bit more before I submit a patch to the main branch. In particular, weirdness may happen if it faces characters which aren’t used in Western European languages. I haven’t tested this yet. (See https://stackoverflow.com/a/8917539/1558022)
If you’re not tied to the dateutil module, you could use datetime instead, which is already locale-aware:
from datetime import datetime, date
import locale
locale.setlocale(locale.LC_ALL, "pt_PT")
datetime.strptime("Ter, 01 Out 2013 14:26:00 -0300",
"%a, %d %b %Y %H:%M:%S %z")
(Note that the %z token is not consistently supported in datetime.)
You could use PyICU to parse a localized date/time string in a given format:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import datetime
import icu # PyICU
df = icu.SimpleDateFormat(
'EEE, dd MMM yyyy HH:mm:ss zzz', icu.Locale('pt_BR'))
ts = df.parse(u'Ter, 01 Out 2013 14:26:00 -0300')
print(datetime.utcfromtimestamp(ts))
# -> 2013-10-01 17:26:00 (UTC)
It works on Python 2/3. It does not modify global state (locale).
If your actual input time string does not contain the explicit utc offset then you should specify a timezone to be used by ICU explicitly otherwise you can get a wrong result (ICU and datetime may use different timezone definitions).
If you only need to support Python 3 and you don't mind setting the locale then you could use datetime.strptime() as #alexwlchan suggested:
#!/usr/bin/env python3
import locale
from datetime import datetime
locale.setlocale(locale.LC_TIME, "pt_PT.UTF-8")
print(datetime.strptime("Ter, 01 Out 2013 14:26:00 -0300",
"%a, %d %b %Y %H:%M:%S %z")) # works on Python 3.2+
# -> 2013-10-01 14:26:00-03:00
The calendar module already has constants for a lot of of languages. I think the best solution is to customize the parser from dateutil using these constants. This is a simple solution and will work for a lot of languages. I didn't test it a lot, so use with caution.
Create a module localeparseinfo.py and subclass parser.parseinfo:
import calendar
from dateutil import parser
class LocaleParserInfo(parser.parserinfo):
WEEKDAYS = zip(calendar.day_abbr, calendar.day_name)
MONTHS = list(zip(calendar.month_abbr, calendar.month_name))[1:]
Now you can use your new parseinfo object as a parameter to dateutil.parser.
In [1]: import locale;locale.setlocale(locale.LC_ALL, "pt_BR.utf8")
In [2]: from localeparserinfo import LocaleParserInfo
In [3]: from dateutil.parser import parse
In [4]: parse("Ter, 01 Out 2013 14:26:00 -0300", parserinfo=PtParserInfo())
Out[4]: datetime.datetime(2013, 10, 1, 14, 26, tzinfo=tzoffset(None, -10800))
It solved my problem, but note that this is an incomplete solution for all possible dates and times. Take a look at dateutil parser.py, specially the parserinfo class variables. Take a look at HMS variable and others. You'll probably be able to use other constants from the calendar module.
You can even pass the locale string as an argument to your parserinfo class.
from dateutil.parser import parse
parse("Ter, 01 Out 2013 14:26:00 -0300",fuzzy=True)
Result:
datetime.datetime(2013, 1, 28, 14, 26, tzinfo=tzoffset(None, -10800))
One could use a context manger to temporarily set the locale and return a custom parserinfo object
Context Manager définition:
import calendar
import contextlib
import locale
from dateutil import parser
#contextlib.contextmanager
def locale_parser_info(localename):
old_locale = locale.getlocale(locale.LC_TIME)
locale.setlocale(locale.LC_TIME, localename)
class InnerParserInfo(parser.parserinfo):
WEEKDAYS = zip(calendar.day_abbr, calendar.day_name)
# dots in abbreviation make dateutil raise a Parser Error exception
MONTHS = list(zip([abr.replace(".", "") for abr in calendar.month_abbr], calendar.month_name))[1:]
try:
yield InnerParserInfo()
finally:
# Restore original locale
locale.setlocale(locale.LC_TIME, old_locale)
The actual function just wraps the call to dateutil.parser.parse in the context manager we just defined, and uses the returned parserinfo object.
def parse_localized(datestr, date_locale="pt_PT"):
with locale_parser_info(date_locale) as parserinfo:
return parser.parse(datestr, parserinfo=parserinfo)

Timezone not available in python, but the system timezone is properly set

As specified in the documentation:
%Z -> Time zone name (no characters if no time zone exists).
According to date, my system has the time zone properly set:
gonvaled#pegasus ~ » date
Sat Sep 28 09:14:29 CEST 2013
But this test:
def test_timezone():
from datetime import datetime
dt = datetime.now()
print dt.strftime('%Y-%m-%d %H:%M:%S%Z')
test_timezone()
Produces:
gonvaled#pegasus ~ » python test_timezone.py
2013-09-28 09:19:10
Without time zone information. Why is that? How can I force python to output time zone info?
I have also trying re-configuring the time zone with tzselect, but has not helped.
Standard Python datetime.datetime() objects do not have a timezone object attached to them. The system time is taken as is.
You'll need to install Python timezone support in the form of the pytz package; timezone definitions change too frequently to be bundled with Python itself.
pytz does not tell you what timezone your machine has been configured with. You can use the python-dateutil module for that; it has a dateutil.tz.gettz() function that returns the timezone currently in use. This is much more reliable than what Python can get from the limited C API:
>>> import datetime
>>> from dateutil.tz import gettz
>>> datetime.datetime.now(gettz())
datetime.datetime(2013, 9, 28, 8, 34, 14, 680998, tzinfo=tzfile('/etc/localtime'))
>>> datetime.datetime.now(gettz()).strftime('%Y-%m-%d %H:%M:%S%Z')
'2013-09-28 08:36:01BST'

How to parse a RFC 2822 date/time into a Python datetime?

I have a date of the form specified by RFC 2822 -- say Fri, 15 May 2009 17:58:28 +0000, as a string. Is there a quick and/or standard way to get it as a datetime object in Python 2.5? I tried to produce a strptime format string, but the +0000 timezone specifier confuses the parser.
The problem is that parsedate will ignore the offset.
Do this instead:
from email.utils import parsedate_tz
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700')
I'd like to elaborate on previous answers. email.utils.parsedate and email.utils.parsedate_tz both return tuples, since the OP needs a datetime.datetime object, I'm adding these examples for completeness:
from email.utils import parsedate
from datetime import datetime
import time
t = parsedate('Sun, 14 Jul 2013 20:14:30 -0000')
d1 = datetime.fromtimestamp(time.mktime(t))
Or:
d2 = datetime.datetime(*t[:6])
Note that d1 and d2 are both naive datetime objects, there's no timezone information stored. If you need aware datetime objects, check the tzinfo datetime() arg.
Alternatively you could use the dateutil module
from email.utils import parsedate
print parsedate('Fri, 15 May 2009 17:58:28 +0000')
Documentation.
It looks like Python 3.3 going forward has a new method parsedate_to_datetime in email.utils that takes care of the intermediate steps:
email.utils.parsedate_to_datetime(date)
The inverse of format_datetime(). Performs the same function as parsedate(), but on
success returns a datetime. If the input date has a timezone of -0000,
the datetime will be a naive datetime, and if the date is conforming
to the RFCs it will represent a time in UTC but with no indication of
the actual source timezone of the message the date comes from. If the
input date has any other valid timezone offset, the datetime will be
an aware datetime with the corresponding a timezone tzinfo.
New in version 3.3.
http://python.readthedocs.org/en/latest/library/email.util.html#email.utils.parsedate_to_datetime
There is a parsedate function in email.util.
It parses all valid RFC 2822 dates and some special cases.
email.utils.parsedate_tz(date) is the function to use. Following are some variations.
Email date/time string (RFC 5322, RFC 2822, RFC 1123) to unix timestamp in float seconds:
import email.utils
import calendar
def email_time_to_timestamp(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
return calendar.timegm(tt) - tt[9]
import time
print(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(email_time_to_timestamp("Wed, 04 Jan 2017 09:55:45 -0800"))))
# 2017-01-04T17:55:45Z
Make sure you do not use mktime (which interprets the time_struct in your computer’s local time, not UTC); use timegm or mktime_tz instead (but beware caveat for mktime_tz in the next paragraph).
If you are sure that you have python version 2.7.4, 3.2.4, 3.3, or newer, then you can use email.utils.mktime_tz(tt) instead of calendar.timegm(tt) - tt[9]. Before that, mktime_tz gave incorrect times when invoked during the local time zone’s fall daylight savings transition (bug 14653).
Thanks to #j-f-sebastian for caveats about mktime and mktime_tz.
Email date/time string (RFC 5322, RFC 2822, RFC 1123) to “aware” datetime on python 3.3:
On python 3.3 and above, use email.utils.parsedate_to_datetime, which returns an aware datetime with the original zone offset:
import email.utils
email.utils.parsedate_to_datetime(s)
print(email.utils.parsedate_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
Caveat: this will throw ValueError if the time falls on a leap second e.g. email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800").
Email date/time string (RFC 5322, RFC 2822, RFC 1123) to “aware” datetime in UTC zone:
This just converts to timestamp and then to UTC datetime:
import email.utils
import calendar
import datetime
def email_time_to_utc_datetime(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
timestamp = calendar.timegm(tt) - tt[9]
return datetime.datetime.utcfromtimestamp(timestamp)
print(email_time_to_utc_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T17:55:45
Email date/time string (RFC 5322, RFC 2822, RFC 1123) to python “aware” datetime with original offset:
Prior to python 3.2, python did not come with tzinfo implementations, so here an example using dateutil.tz.tzoffset (pip install dateutil):
import email.utils
import datetime
import dateutil.tz
def email_time_to_datetime(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
tz = dateutil.tz.tzoffset("UTC%+02d%02d"%(tt[9]//60//60, tt[9]//60%60), tt[9])
return datetime.datetime(*tt[:5]+(min(tt[5], 59),), tzinfo=tz)
print(email_time_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
If you are using python 3.2, you can use the builtin tzinfo implementation datetime.timezone: tz = datetime.timezone(datetime.timedelta(seconds=tt[9])) instead of the third-party dateutil.tz.tzoffset.
Thanks to #j-f-sebastian again for note on clamping the leap second.

Categories

Resources