1

I am developing an iOS application that needs to sync with a Python based REST service on GAE.

In the python backend I create my timestamps like this:

def create_timestamp(date):
    midnight = datetime.time(0)
    date_midnight_time = datetime.datetime.combine(date.date(), midnight)
    return calendar.timegm(date_midnight_time.utctimetuple())

I pass in the function above datetime.datetime.today(). This would return for 27 Oct 2013 00:00:00 the value 1382832000.

On iOS there is a buildin function for that:

nextDate is set to today's date a bit complicated due an algorithm:

NSDate *date = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit) fromDate:date];

[components setDay:27];
NSDate *nextDate = [calendar dateFromComponents:components];

[nextDate timeIntervalSince1970] which returns for 2013-10-27 00:00:00 BST the value 1382828400.000000

There is some discrepancy though.

  1. Maybe its because that Python side is UTC and iOS shows the time in BST by default and I need to address that. As of last night the British Summer time is no more, but iOS still reports BST. Thats confusing though as a NSDate object is always in UTC from my understanding....

  2. Once its working, is it safe to cast the iOS double value to int, in order to get a round integer number similar to the Python side?

Houman
  • 64,245
  • 87
  • 278
  • 460

1 Answers1

0

I know this is old, but I thought I'd respond, since this particular issue is something I've been looking for an answer for for a while:

The IOS timestamp you give refers to the correct midnight for GMT of that date. The python timestamp you give refers to one hour earlier (11:00 pm on the prior day).

This took me forever to find, and it's a pretty smart way of doing it (particularly when you consider the many more circuitous options I've seen):

I tried this, and it works nicely when trying to get the timestamp for a datetime in your local zone (but..):

from datetime import datetime

def dt_to_timestamp(dt_object):
    """Not really a good, universal solution"""
    return eval(dt_object.strftime('%s.%f'))

dt_to_timestamp(datetime.now()) - time.time()
# -0.0002155303955078125

..but it fails pretty badly once it comes to looking at objects outside of your local zone:

from tzlocal import get_localzone
from pytz import utc

utc_now = datetime.now(tz=localzone).astimezone(utc)
dt_to_timestamp(utc_now) - time.time()
# 21599.98956131935, more commonly known as 21600 -- my offset from UTC

This is what I finally ended up with:

from datetime import datetime
from pytz import utc

def dt_to_timestamp(dt_object):
    """Provides timestamp for any zone-aware datetime object.
    Works with Python 2.7 and Python 3.3, possibly others.
    Raises TypeError when naive datetime objects are given.
    """
    epoch = datetime(1970, 1, 1, tzinfo=utc)
    delta = dt_object - epoch
    return delta.total_seconds()

# example usage:
from tzlocal import get_localzone
ts = 1382832000
utc_dt = utc.localize(datetime.utcfromtimestamp(ts))
local_dt = utc_dt.astimezone(get_localzone())

ts == dt_to_timestamp(utc_dt) == dt_to_timestamp(local_dt)
# True    

It handles aware datetime objects accurately, whatever their timezone. If the caller doesn't know the timezone in order to turn it into an aware timezone, then there are other problems. :-) I'm of the opinion that one should always use an aware datetime objects if possible, and when not using aware datetime objects, use UTC datetimes.

I found the info for this answer (amongst a lot of other detail) here.

Community
  • 1
  • 1
Mr. B
  • 2,536
  • 1
  • 26
  • 26