2

Usually what I do if I want to convert time zone is the following

# local interpreted as pst to utc

utc = pytz.utc
pst = pytz.timezone('America/Los_Angeles')


start_time_str = time.strftime('%Y-%m-%d %H:%M:%S', \
  time.localtime(start_time))
start_time_datetime = \
  datetime.datetime.strptime(start_time_str, "%Y-%m-%d %H:%M:%S")

start_time_datetime = \
  start_time_datetime.replace(tzinfo=pst).astimezone(utc)

Now I want to do similar stuff such that I want localtime convert to pst

localtime = datetime.datetime.fromtimestamp(time.mktime(
            time.localtime()))

I am not exactly sure how would you achieve this

Any help would be appreciated

Andy
  • 49,085
  • 60
  • 166
  • 233
Kevin
  • 371
  • 3
  • 7
  • 14
  • similar to http://stackoverflow.com/questions/4974712/python-setting-a-datetime-in-a-specific-timezone-without-utc-conversions – LittleQ Jun 22 '15 at 19:38
  • what is your input? Is it a Unix time `start_time` (a number)? Why do you call `strftime()` only to call `strptime()` (the opposite conversion) immediately? What is the purpose of `localtime` calculation (are you aware of `datetime.now()`)? – jfs Jun 23 '15 at 07:36

3 Answers3

6

Two things:

  1. The "America/Los_Angeles" identifier represents the entire Pacific time zone, including both PST and PDT. It will use the either -8 or -7 as the time zone offset depending on the specific date and time it is used on.

  2. Calling replace(tzinfo=...) is a mistake. Use localize instead. See the pytz documentation. This is discussed in the introduction and in the very first example.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • +1 for mentioning `localize`, it's very important. You can get some very weird errors if you use `replace`, which is the same as specifying the time zone object in the `datetime` constructor. – Mark Ransom Jun 22 '15 at 22:29
  • You can call `.replace(tzinfo=...)` and then `.localize()` or `.astimezone()`. In fact, you probably do want to replace `tzinfo` if it's `None` so that the `datetime` object is no longer naive. I would not use it for anything, though, until I run `localize` on it, and that's easy peasy once you define the originating timezone. I think it is a naive datetime object where one more likely might see weird errors. – ingyhere Nov 16 '19 at 19:50
3

Your code contains unnecessary (calling strptime after strftime) or just wrong (.replace()) conversions.

To create an aware datetime object given "seconds since epoch" start_time (a value returned by time.time()):

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

tz = pytz.timezone('America/Los_Angeles')
start_time_datetime = datetime.fromtimestamp(start_time, tz)

As @Matt Johnson mentions, 'America/Los_Angeles' timezone id produces time with PST or PDT tzname depending on the date. No conversion is necessary.

The last code example in your question has both unnecessary conversions and may fail in some cases. If the intent is to get the current time in the local timezone as an aware datetime object then you could use tzlocal module:

#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # $ pip install tzlocal

local_timezone = get_localzone() # pytz timezone corresponding to the  local time
current_localtime = datetime.now(local_timezone)
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

First, as a note, local time is either Standard Time or Daylight Savings Time -- it cannot be both simultaneously. I believe what you are really getting at is asking whether there is a way to tell if a time is either a Daylight Savings Time or not. In other words, given a specific day, is a particular time in Daylight Savings Time? Another common use case is converting tabular data pegged at a specific time offset to the current correct time.

Okay, I can think of three ways to do this.

(1) You can convert the datetime into a time object and look at the .tm_isdst property, similar to this answer. You can do a test on it to see if that property equals one and then subtract a timedelta of one hour.

>>> time.localtime()
time.struct_time(tm_year=2019, tm_mon=11, tm_mday=16, tm_hour=12, 
tm_min=36, tm_sec=32, tm_wday=5, tm_yday=320, tm_isdst=0)
>>> time.localtime().tm_isdst
0

(2) Second way is to crawl month by month over noon on the fifteenth of each month and check if the offset varies. (Note that some areas do not implement DST.) The greater value indicates a skip ahead for Daylight Savings Time. (For instance, PDT is UTC -7 while PST is UTC -8.) From those values you can calculate the time difference. Then you can test your time by checking the offset to see if it is in Standard Time or Daylight Savings Time. Offest is checked this way:

>>> my_special_pdt_datetime.strftime('%z') 
'-0700'

(3) And, maybe the easiest, is to calculate the existing offset by getting offset = datetime.datetime.utcnow() - datetime.datetime.now() and then comparing that to the known offset from pytz:

>>> pytz.timezone('US/Pacific').localize(datetime.datetime(2019,1,1)).strftime('%z')
'-0800'
ingyhere
  • 11,818
  • 3
  • 38
  • 52
  • Are you saying that it isn't *valid* to ask to convert PDT to PST (or vice versa)? In my case, I know that a timestamp `8/28/20 5:34:00` is in PST with timezone *America/Los_Angeles*. I'm trying to convert it to UTC and expect the UTC timestamp to be `8/28/20 13:34:00`. But `pytz.localize()` interprets `8/28/20 5:34:00` as PDT and adds the wrong offset, giving me `8/28/20 12:34:00`. – Minh Tran Aug 28 '20 at 14:54
  • @MinhTran Standard time and daylight savings time are mutually exclusive, so you're either in one or the other. On August 28, 2020, we are in PDT, so Python will exclusively report PDT values. So, it is technically feasible but not explicitly legitimate. If you want to convert from PST to PDT for any given time (but not date) you just add an hour. Or, you can detect if you are within PDT currently using the `time.localtime().tm_isdst` parameter and add the hour based on that parameter. – ingyhere Aug 28 '20 at 18:15