© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
A. DanialPython for MATLAB Developmenthttps://doi.org/10.1007/978-1-4842-7223-7_5

5. Dates and Times

Albert Danial1  
(1)
Redondo Beach, CA, USA
 

Temporal data appears frequently in computational work. Measurements recorded from sensors, economic results, stock prices, time-stepping numeric simulations, and so on are useless without accompanying time values. In this chapter, we’ll cover Python’s datetime module which offers capabilities similar to MATLAB’s data type of the same name.

5.1 Time

Python’s time module has functions to return the current time, either in the local timezone or UTC; measure CPU or elapsed time; and sleep for a desired amount of time.

5.1.1 Current Time

The Python time.time() function returns the same value as posixtime(datetime()) in MATLAB, a double-precision representation of current time in Unix epoch seconds, a continuous increment of seconds since midnight, January 1, 1970, ignoring leap seconds, to a resolution of a microsecond. Among other things, it is useful in Python for computing elapsed time of code segments.

The time.strftime() function returns the current time according to a desired format:

MATLAB:

Python:

>> format long e

>> posixtime(datetime())

    1.572210959845713e+09

>> t = datetime;

>> datestr(t,'yyyy-mm-dd HH:MM:ss')

    '2019-10-27 14:25:26'

In : import time

In : time.time()

Out: 1572210959.845713

In : time.strftime('%Y-%m-%d %H:%M:%S')

Out: '2019-10-27 14:25:26'

5.1.2 Time String Formats

Format arguments for strftime() include all arguments accepted by the 1989 C standard library function of the same name plus a few others. In some cases, the output depends on the computer’s locale setting. This can be revealed by with the command locale in a terminal on Linux and macOS and with systeminfo in a command prompt on Windows (look for “System Locale” in the output). Examples in Table 5-1 use locale settings of en_US and de_DE, as taken from the Python project’s documentation.

MATLAB equivalent format strings for the datestr() function are given if the format is supported.
Table 5-1

strftime() and strptime() format codes

Python Directive

Meaning

Examples

MATLAB Equivalent in datestr()

%a

Abbreviated weekday

Sun, Mon (en_US)

So, Mo (de_DE)

ddd

%A

Abbreviated weekday

Sunday (en_US)

Sonntag (de_DE)

dddd

%w

Weekday as integer

Python: 0 (Sunday) … 6

MATLAB: 1 (Sunday) … 7

e

%d

Two-digit day of month

01, …, 31

dd

%b

Abbreviated month

Jan, Dec (en_US)

Jan, Dez (de_DE)

MMM

%B

Month

January (en_US)

Januar (de_DE)

MMMM

%m

Two-digit month

01, …, 12

MM

%y

Two-digit year

99, 00, …, 19

yy

%Y

Four-digit year

1999, 2000, …, 2019

yyyy or u

%H

Two-digit hour, 0–23

00, …, 23

HH

%I

Two-digit hour, 0–11

00, …, 11

HH PM

   

(output includes "PM")

%p

AM or PM

AM, PM (en_US)

am, pm (de_DE)

AM or PM

%M

Two-digit minute

00, …, 59

mm

%S

Two-digit seconds

00, …, 59

ss

%f

Six-digit microseconds

000000, …, 999999

S .. SSSSSSSSS

(tenth second to nanoseconds)

%z

UTC offset

±HHMM[SS[.ffffff]]

+0000, –0900015

Z

%j

Three-digit day of year

001, …, 366

DDD

%U

Two-digit week of year

(week starts on Sunday)

00, …, 53

Not available

%W

Two-digit week of year

(week starts on Monday)

00, …, 53

Not available

%c

Locale-specific date and time

Sun Oct 27 16:57:47 2019 (en US)

datetime() default

%x

Locale-specific date

10/27/19 (en_US)

27.10.2019 (de_DE)

Not available

%X

Locale-specific time

17:00:53 (en_US)

17:00:53 (de_DE)

Not available

%%

Literal %

%

%

5.1.3 tic, toc; %timeit

MATLAB’s tic and toc compute elapsed CPU time of commands nested between them. time.time() in Python can do the same thing, but with more typing:

MATLAB:

Python:

>> N = 1000;

>> tic

>> a = eig(rand(N))

>> toc

Elapsed time: 1.57437 seconds.

In : import time; import numpy as np

In : N = 1000

In : tic = time.time()

In : a = np.linalg.eig(np.random.rand(N,N))

In : time.time() - tic

Out: 1.2564113140106201

The difference of calls to time.time() is useful in a Python program, but when working interactively in ipython, it is easier to use its “magic” command %timeit to measure how long a command takes:

Python:
In : %timeit np.linalg.eig(np.random.rand(1000,1000))
1.2 s ± 18.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit will run the command several times (seven in the preceding example) and return the mean time over all runs.

5.2 Dates

Python has three standard modules for working with dates, each with different capabilities:
  • datetime is the most wide-ranging and will be the focus of discussion in this section. It has many functions to simplify computations with dates and perform conversions.

  • date is more or less a subset of datetime and is useful when working purely with dates, without associated time within a day.

  • calendar has functions to determine if a year is a leap year, the day of the week for a given date, and the number of days in a month.

5.2.1 datetime Objects to and from Strings

The datetime module , like the time module, uses the strftime() function to print a date in a desired format:

MATLAB:

Python:

>> now = datetime()

   28-Oct-2019 21:16:36

>> datetime(now,'Format',...

            'u-MM-dd hh:mm')

   2019-10-28 21:16

In : from datetime import datetime

In : datetime.now()

Out: datetime(2019, 10, 28, 21,

16, 36, 225635)

In : datetime.now().strftime(

'%Y-%m-%d %H:%M')

Out: '2019-10-28 21:16'

Both datetime and time have a similarly named function, strptime(), that does the opposite: it takes a string containing a date and a second string describing the format, then returns a Python variable which can subsequently be used to perform date computations.

Conveniently, strptime() uses the same format directives (Table 5-1) to parse dates from strings as strftime() uses to print dates in a desired format. Creating a datetime object from the string “Aug 12 04:05:51 2006” would be done like this:

MATLAB:

Python:

>> S ='Aug 12 04:05:51 2006';

>> dt=datetime(S,'InputFormat',...

           'MMM dd HH:mm:SS yyyy')

dt =

  datetime

  12-Aug-2006 04:05:00

In : from datetime import datetime

In : S = 'Aug 12 04:05:51 2006'

In : dt = datetime.strptime(S,

...:       '%b %d %H:%M:%S %Y')

In : dt

Out: datetime.datetime(

        2006, 8, 12, 4, 5, 51)

5.2.2 Time Deltas

The datetime module function timedelta() creates time offsets that work like duration objects in MATLAB. This example prints a week’s worth of Martian solar days (which last 24 hours, 39 minutes, and 35.244 seconds), starting at noon on June 28, 1986:

MATLAB:

Python:

Mars_day = duration(...

            24,39,35.244)

Start = datetime(...

        1986,6,28,12,0,0)

for i = 0:6

    Start + i*Mars_day

end

28-Jun-1986 12:00:00

29-Jun-1986 12:39:35

30-Jun-1986 13:19:10

01-Jul-1986 13:58:45

02-Jul-1986 14:38:20

03-Jul-1986 15:17:56

04-Jul-1986 15:57:31

from datetime import datetime, timedelta

Mars_day = timedelta(hours=24,

    minutes=39, seconds=35.244)

Start = datetime(1986,6,28,12)

for i in range(7):

    print(Start + i*Mars_day)

1986-06-28 12:00:00

1986-06-29 12:39:35.244000

1986-06-30 13:19:10.488000

1986-07-01 13:58:45.732000

1986-07-02 14:38:20.976000

1986-07-03 15:17:56.220000

1986-07-04 15:57:31.464000

timedelta objects have a method, .total_seconds(), that returns the number of seconds represented by the delta. The difference of two datetime objects is a timedelta, so we can easily determine how much time has elapsed between two dates:

MATLAB:

Python:

Jul4 = '1976-07-04 12:00';

Aug1 = '1976-08-01 18:00';

J=datetime(Jul4,'InputFormat',...

           'yyyy-MM-dd HH:mm')

A=datetime(Aug1,'InputFormat',...

           'yyyy-MM-dd HH:mm')

duration(A-J,'Format','s')

    2.4408e+06 sec

from datetime import datetime as DT

Jul4 = '1976-07-04 12:00'

Aug1 = '1976-08-01 18:00'

J = DT.strptime(Jul4, '%Y-%m-%d %H:%M')

A = DT.strptime(Aug1, '%Y-%m-%d %H:%M')

(A - J).total_seconds()

Out: 2440800.0

MATLAB and Python also allow one to compute ratios of time deltas. This example prints the number of Martian days in an Earth year:

MATLAB:

Python:

>> Mars_day = duration(...

                24,39,35.244);

>> duration(years(1))/Mars_day

    355.47

In : Mars_day = timedelta(hours=24,

...:     minutes=39, seconds=35.244)

In : timedelta(days=365.24)/Mars_day

Out: 355.4677472922519

5.3 Timezones

Datetime objects in both Python and MATLAB, by default, lack timezone information; they merely reflect the date and time of the host computer.

Python datetime objects can be made timezone-aware by populating the optional tzinfo or tz keywords in calls to datetime(), datetime.now(), or datetime.fromtimestamp() functions. Two Python modules that can create tzinfo objects are pytz and dateutil.tz. (Python 3.9 introduced the zoneinfo module which is discussed in Section 5.5. MATLAB 2020b, the version used in this book, predates Python 3.9 and therefore does not support it.) Although pytz has more features, the timezones from dateutil.tz yield more accurate results for corner cases, such as computing time deltas that span daytime/standard time transitions [1].

In this section, our only use of pytz will be to list all known timezone strings—like MATLAB’s timezones command—something dateutil.tz can’t do:

MATLAB:

Python:

>> timezones

In : import pytz

In : pytz.all_timezones

Out:

['Africa/Abidjan',

 'Africa/Accra',

 'Africa/Addis_Ababa',

 'Africa/Algiers',

     ...

 'US/Pacific',

 'US/Samoa',

 'UTC',

 'Universal',

 'W-SU',

 'WET',

 'Zulu']

Timezone names in MATLAB’s table match the names returned by pytz.all_timezones.

With a valid timezone name pulled from the preceding list, we’re ready to create a timezone-aware datetime object. Note that datetime’s output identifies the operating system’s file from which timezone information was taken (’/usr/share/zoneinfo/America/Los_Angeles’ in this example):

MATLAB:

Python:

>> T = datetime(2020,2,14,...

        13,30,25,'TimeZone',...

        'America/Los_Angeles')

T =

   14-Feb-2020 13:30:25

>> T.TimeZone

    'America/Los_Angeles'

>> datetime(T,'Format',...

    'yyyy-MM-dd''T'...

    'HH:mm:ss''.''SSSSSS')

   2020-02-14T13:30:25.000000

>> datetime(T,'Format','Z')

   -0800

In : from datetime import datetime

In : from dateutil import tz

In : LA_tz = tz.gettz('America/Los_Angeles')

In : T = datetime(2020,2,14,13,30,25,

...:     tzinfo=LA_tz)

In : T

Out: datetime.datetime(2020,2,14,13,30,25,

   tzinfo=tzfile(

   '/usr/share/zoneinfo/America/Los_Angeles'))

In : T.isoformat()

Out: '2020-02-14T13:30:25-08:00'

In : T.utcoffset()

Out: datetime.timedelta(days=-1,seconds=57600)

Displaying a timezone-aware datetime object in any other desired timezone is easily done:

MATLAB:

Python:

>> datetime(T,'TimeZone',...

           'Asia/Tokyo')

   15-Feb-2020 06:30:25

In : Tokyo_tz = tz.gettz('Asia/Tokyo')

In : T.astimezone(Tokyo_tz)

Out: datetime.datetime(2020,2,15,6,30,25,

         tzinfo=tzfile(

         '/usr/share/zoneinfo/Asia/Tokyo'))

5.3.1 UTC vs. Local Time

UTC, also called Zulu or Greenwich Mean Time, is the preferred timezone for recording events that span wide geographic areas. MATLAB and Python have several functions that explicitly work with UTC time as opposed to the local time on an individual computer.

Paradoxically, the datetime functions that return UTC time, datetime.utcnow() and datetime.utcfromtimestamp(), do not set tzinfo, and so they return timezone-unaware objects. In other words, the numeric values for day, hour, minute, and so on are correct, but there is no underlying metadata stating that this is the UTC timezone. If computational accuracy for subsequent date computations is important, the proper way to define UTC time is to use the functions without utc in their names and explicitly pass in tz=dateutil.tz.UTC [2]:

Python:
In : import time
In : from datetime import datetime
In : from dateutil import tz
In : datetime.now()  # local time (Los Angeles)
Out: datetime.datetime(2019, 11, 9, 18, 20, 57, 118448)
#    create UTC time from current time -- but without an associated timezone!
In : datetime.utcnow()
Out: datetime.datetime(2019, 11, 10, 2, 20, 57, 118448)
#    the better way to create UTC time from current time
In : datetime.now(tz=tz.UTC)
Out: datetime.datetime(2019, 11, 10, 2, 20, 57, 118448, tzinfo=tzutc())
In : epoch_sec = time.time()
In : epoch_sec
Out: 1573352547.984918
In : datetime.fromtimestamp(epoch_sec)
Out: datetime.datetime(2019, 11, 9, 18, 22, 27, 984918)
#    the wrong way to create UTC time from epoch seconds
In : datetime.utcfromtimestamp(epoch_sec)
Out: datetime.datetime(2019, 11, 10, 2, 22, 27, 984918)
#    the right way to create UTC time from epoch seconds
In : datetime.fromtimestamp(epoch_sec, tz=tz.UTC)
Out: datetime.datetime(2019, 11, 10, 2, 22, 27, 984918, tzinfo=tzutc))

Similar conversions in MATLAB look like this:

MATLAB:
>> a = datetime('now')  % computer is in Los Angeles timezone
   21-Nov-2023 11:28:52
>> a = datetime('now','TimeZone','America/Los_Angeles')
   21-Nov-2023 11:28:52
>> a = datetime('now','TimeZone','UTC')
   21-Nov-2023 18:28:52
>> epoch_sec = convertTo(a,'posixtime')
     1.700591332042366e+09
>> datetime(epoch_sec,'convertfrom','posixtime')
   21-Nov-2023 18:28:52

5.4 Time Conversions to and from datetime Objects

Section 5.2.1 showed how a datetime object can be converted to a string and how a string can be parsed into a datetime object. In this section, we explore additional format conversions to and from datetime objects using local time and UTC. The examples employ the following imports:

Python:
In : from datetime import datetime
In : import pytz
In : import time

5.4.1 Unix Epoch Seconds

Unix epoch seconds are independent of timezone, so the conversion from a timezone-enabled datetime object can be misleading:

Python:
In : epoch_sec = time.time()
In : epoch_sec
Out: 1572630202.1339452
In : dtZ = datetime.datetime.utcfromtimestamp( epoch_sec )
In : dtL = datetime.datetime.fromtimestamp(    epoch_sec )
In : dtZ
Out: datetime.datetime(2019, 11, 1, 17, 43, 22, 133945)
In : dtL
Out: datetime.datetime(2019, 11, 1, 10, 43, 22, 133945)
In : recovered_epoch_secZ = dtZ.timestamp()
In : recovered_epoch_secL = dtL.timestamp()
In : recovered_epoch_secZ
Out: 1572655402.133945
In : recovered_epoch_secL
Out: 1572630202.133945

For circular consistency, the Unix epoch value must be converted to the timezone where it was initially measured.

5.4.2 ISO 8601 Time String

Time strings in the ISO 8601 standard can have one of these forms:
  • 2019-11-01T15:54:04

  • 2019-11-01T15:54:04Z

  • 2019-11-01T15:54:04+00:00

Although the datetime module includes a .fromisoformat() function, curiously the function does not accept the trailing “Z” (for “Zulu,” also known as UTC); one must either omit the timezone designator or specify it as a numeric offset.

Also, since the ISO format function with a timezone offset explicitly sets the timezone, the local time variable is explicitly computed from the timezone-aware datetime object using the .astimezone() method :

Python:
In : dtZ = datetime.fromisoformat('2019-11-01T15:54:04+00:00')
In : TZ_LA = pytz.timezone("America/Los_Angeles")
In : dtL = dtZ.astimezone(TZ_LA)
In : dtZ
Out: datetime.datetime(2019, 11, 1, 15, 54, 4,
        tzinfo=datetime.timezone.utc)
In : dtL
Out: datetime.datetime(2019, 11, 1, 8, 54, 4,
        tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>)
In : recovered_isoZ = dtZ.isoformat()
In : recovered_isoZ
Out: '2019-11-01T15:54:04+00:00'
In : recovered_isoL = dtL.isoformat()
In : recovered_isoL
Out: '2019-11-01T08:54:04-07:00'

5.4.3 Julian Date; Modified Julian Date; GPS Time

Anaconda comes with a module, astropy, which has powerful time conversion capabilities related to astronomy. These include Julian, Modified Julian, FITS, UT1, TAI, and GPS references.

The following examples use the US/Pacific timezone:

Python:
In : from astropy.time import Time
In : dt = datetime.fromisoformat('2019-11-03T05:29:04-07:00')
In : dt
Out: datetime.datetime(2019, 11, 3, 5, 29, 4,
              tzinfo=datetime.timezone(
                         datetime.timedelta(days=-1, seconds=61200)))
# from datetime to MJD, JD, GPS:
In : astropy_t = Time( dt )
In : astropy_t
Out: <Time object: scale='utc' format='datetime' value=2019-11-03 12:29:04>
In : astropy_t.mjd
Out: 58790.52018518518
In : astropy_t.jd
Out: 2458791.020185185
In : astropy_t.gps
Out: 1256819362.0
# MJD, JD, GPS to datetime:
In : Time( 58790.52018518518, format='mjd').datetime
Out: datetime.datetime(2019, 11, 3, 12, 29, 4)
In : Time( 2458791.020185185 , format='jd').datetime
Out: datetime.datetime(2019, 11, 3, 12, 29, 3, 999995)
In : Time( 1256819362.0, format='gps').datetime
Out: datetime.datetime(2019, 11, 3, 12, 29, 41)

5.5 zoneinfo in Python >= 3.9

Python 3.9 (not supported by MATLAB 2020b, Section 2.​7) introduced the module zoneinfo to improve timezone support. zoneinfo’s primary benefit is its rigorous treatment of time computations across daylight savings transitions. In addition, like pytz, zoneinfo includes a mechanism to list all known timezone names, making it unnecessary to import pytz merely to access its list of timezones, pytz.all_timezones.

5.5.1 List Available Timezones

Python 3.9:
In : import zoneinfo
In : zoneinfo.available_timezones()
Out:
{'Africa/Abidjan',
 'Africa/Accra',
 'Africa/Addis_Ababa',
 'Africa/Algiers',
 'Africa/Asmara',
 'Africa/Asmera',
   [...]
 'UTC',
 'Universal',
 'W-SU',
 'WET',
 'Zulu',
 'build/etc/localtime'}

5.5.2 Date Increments Across Daylight Savings Transition

This example demonstrates correct handling of standard time to daylight savings time transition using rules for the Los Angeles entry in the timezone database:

Python 3.9:
import zoneinfo
from datetime import datetime, timedelta
LA_tz = zoneinfo.ZoneInfo("America/Los_Angeles")
Start = datetime(2022, 3, 9, 10, tzinfo=LA_tz)
for i in range(7):
    day = Start + timedelta(days=i)
    print(day, day.tzname())
# output:
2022-03-09 10:00:00-08:00 PST
2022-03-10 10:00:00-08:00 PST
2022-03-11 10:00:00-08:00 PST
2022-03-12 10:00:00-08:00 PST
2022-03-13 10:00:00-07:00 PDT
2022-03-14 10:00:00-07:00 PDT
2022-03-15 10:00:00-07:00 PDT

5.6 References

  1. [1]

    Paul Ganssle. “pytz: The Fastest Footgun in the West.” In: (Mar. 2018). URL: https://blog.ganssle.io/articles/2018/03/pytz-fastest- footgun.html

     
  2. [2]

    Paul Ganssle. “Stop using utcnow and utcfromtimestamp.” In: (Nov. 2019). URL: https://blog.ganssle.io/articles/2019/11/utcnow. html

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.150.56