Package: zulu
A drop-in replacement for native datetimes that embraces UTCLinksProject:https://github.com/dgilland/zuluDocumentation:https://zulu.readthedocs.ioPyPI:https://pypi.python.org/pypi/zulu/Github Actions:https://github.com/dgilland/zulu/actionsFeaturesAll datetime objects converted and stored as UTC.Parses ISO8601 formatted strings and POSIX timestamps by default.Timezone representation applied only during string output formatting or when casting to native datetime object.Drop-in replacement for native datetime objects.Python 3.6+QuickstartInstall using pip:pip3 install zuluimportzuluzulu.now()# <Zulu [2016-07-25T19:33:18.137493+00:00]>dt=zulu.parse('2016-07-25T19:33:18.137493+00:00')# <Zulu [2016-07-25T19:33:18.137493+00:00]>dt=zulu.create(2016,7,25,19,33,18,137493)# <Zulu [2016-07-25T19:33:18.137493+00:00]>dt.isoformat()# '2016-07-25T19:33:18.137493+00:00'dt.timestamp()# 1469475198.137493dt.naive# datetime.datetime(2016, 7, 25, 19, 33, 18, 137493)dt.datetime# datetime.datetime(2016, 7, 25, 19, 33, 18, 137493, tzinfo=<UTC>)dt.format('%Y-%m-%d')# 2016-07-25dt.format('YYYY-MM-dd')# 2016-07-25dt.format("E, MMM d, ''YY")# "Mon, Jul 25, '16"dt.format("E, MMM d, ''YY",locale='de')# "Mo., Juli 25, '16"dt.format("E, MMM d, ''YY",locale='fr')# "lun., juil. 25, '16"dt.shift(hours=-5,minutes=10)# <Zulu [2016-07-25T14:43:18.137493+00:00]>dt.replace(hour=14,minute=43)# <Zulu [2016-07-25T14:43:18.137493+00:00]>dt.start_of('day')# <Zulu [2016-07-25T00:00:00+00:00]>dt.end_of('day')# <Zulu [2016-07-25T23:59:59.999999+00:00]>dt.span('hour')# (<Zulu [2016-07-25T19:00:00+00:00]>, <Zulu [2016-07-25T19:59:59.999999+00:00]>)dt.time_from(dt.end_of('day'))# '4 hours ago'dt.time_to(dt.end_of('day'))# 'in 4 hours'list(zulu.range('hour',dt,dt.shift(hours=4)))# [Zulu [2016-07-25T19:33:18.137493+00:00]>,#  Zulu [2016-07-25T20:33:18.137493+00:00]>,#  Zulu [2016-07-25T21:33:18.137493+00:00]>,#  Zulu [2016-07-25T22:33:18.137493+00:00]>]list(zulu.span_range('minute',dt,dt.shift(minutes=4)))# [(Zulu [2016-07-25T19:33:00+00:00]>, Zulu [2016-07-25T19:33:59.999999+00:00]>),#  (Zulu [2016-07-25T19:34:00+00:00]>, Zulu [2016-07-25T19:34:59.999999+00:00]>),#  (Zulu [2016-07-25T19:35:00+00:00]>, Zulu [2016-07-25T19:35:59.999999+00:00]>),#  (Zulu [2016-07-25T19:36:00+00:00]>, Zulu [2016-07-25T19:36:59.999999+00:00]>)]zulu.parse_delta('1w 3d 2h 32m')# <Delta [10 days, 2:32:00]>zulu.parse_delta('2:04:13:02.266')# <Delta [2 days, 4:13:02.266000]>zulu.parse_delta('2 days, 5 hours, 34 minutes, 56 seconds')# <Delta [2 days, 5:34:56]>Why Zulu?Why zulu instead ofnative datetimes:Zulu has extended datetime features such asparse(),format(),shift(), andpython-dateutiltimezone support.Parses ISO8601 and timestamps by default without any extra arguments.Easier to reason aboutZuluobjects since they are only ever UTC datetimes.Clear delineation between UTC and other time zones where timezone representation is only applicable for display or conversion to native datetime.Supports more string parsing/formatting options usingUnicode date patternsas well asstrptime/strftimedirectives.Why zulu instead ofArrow:Zulu is a drop-in replacement for native datetimes (inherits fromdatetime.datetime). No need to convert usingarrow.datetimewhen you need a datetime (zulu is always a datetime).Stricter parsing to avoid silent errors. For example, one might expectarrow.get('02/08/1987','MM/DD/YY')to fail (input does not match format) but it gladly returns<Arrow[2019-02-08T00:00:00+00:00)whereaszulu.parse('02/08/1987','%m/%d/%y')throwszulu.parser.ParseError: Value "02/08/1987" does not match any format in['%m/%d/%y'].Avoids timezone/DST shifting bugs by only dealing with UTC datetimes when applying timedeltas or performing other calculations.Supportsstrptime/strftimeas well asUnicode date patternsfor string parsing/formatting.Special ThanksSpecial thanks goes out to the authors/contributors of the following libraries that have made it possible forzuluto exist:Babeliso8601python-dateutilpytimeparsepytzFor the full documentation, please visithttps://zulu.readthedocs.io.Changelogv2.0.1 (2023-11-20)Add support for Python 3.12Replace usage of deprecateddatetime.utcnowanddatetime.utcfromtimestamp.v2.0.0 (2021-06-26)Drop support for Python 3.4 and 3.5.v1.3.1 (2021-06-26)Fix compatibility issue with Python 3.4 and 3.5 by replacing f-string usage with string-format.v1.3.0 (2021-01-07)Add Python 3.9 support.Fix bug inZulu.time_from,Zulu.time_to,Zulu.time_from_now, andZulu.time_to_nowwhere keyword arguments weren’t passed to underlyingDelta.formatcall.Fix bug inZulu.formatwhere “YY” and “YYYY” format patterns would return the year in “Week of Year” based calendars instead of the regular calendar year.v1.2.0 (2020-01-14)Add Python 3.8 support.Add'week'option toZulu.start_of,Zulu.end_of,Zulu.span, andZulu.span_range. ThanksThomasChiroux!Fix bug inZulu.astimezonein Python 3.8 due to change in return type fromsuper().asdatetime. In Python<=3.7,super().asdatetimereturned as instance ofdatetime, but in Python 3.8 another instance ofZuluwas returned instead.Zulu.astimezonewill now return adatetimeinstance in Python 3.8.v1.1.1 (2019-08-14)Remove unused parameter inzulu.Timer.__init__().v1.1.0 (2018-11-01)Addfoldattribute support toZulu.Addzulu.to_secondsfor converting units of time to total number of seconds.Addzulu.Timerclass that can be used to track elapsed time (like a stopwatch) or as a countdown timer.v1.0.0 (2018-08-20)Drop support for Python 2.7.v0.12.1 (2018-07-16)Support Python 3.7.v0.12.0 (2017-07-11)AddZulu.datetimetuple().AddZulu.datetuple().RemoveZulu.__iter__method. (breaking change)RemoveDelta.__iter__method. (breaking change)v0.11.0 (2017-06-28)Add Python 3.6 support.AddDelta.__iter__method that yields 2-element tuples likeZulu.__iter__. Delta values are normalized into integer values distributed from the higher units to the lower units.AddDelta.__float__andDelta.__int__methods for converting to seconds.AddZulu.__float__andZulu.__int__methods for converting to epoch seconds.Fix issue in Python 3.6 wherezulu.now()returned a naive datetimeZuluinstance.MakeZulu.__iter__yield 2-element tuples containing(unit, value)like(('year',2000), ('month', 12),...)so it can be converted to adictwith proper keys easier. (breaking change)Remove previously deprecatedzulu.delta()function. Usezulu.parse_delta()instead. (breaking change)Rename modules: (breaking change)zulu.datetime->zulu.zuluzulu.timedelta->zulu.deltav0.10.1 (2017-02-15)Provide fallback for the default value oflocaleinDelta.format()when a locale is not known via environment variables.v0.10.0 (2017-02-13)Addzulu.parse_deltaas alias forDelta.parse.Deprecatezulu.deltain favor ofzulu.parse_delta.Allow first argument toZulu(),Zulu.parse(), andzulu.parse()to be adictcontaining keys corresponding to initialization parameters.Fix error message for invalid timezone strings so that the supplied string is shown correctly.v0.9.0 (2016-11-21)Requirepython-dateutil>=2.6.0. (breaking change)Replace usage ofpytztimezone handling for strings withdateutil.tz.gettz. Continue to supportpytztimezones duringZulu()object creation. (breaking change).Replace default UTC timezone withdateutil.tz.tzutc(). Was previouslypytz.UTC. (breaking change)Replace local timezone withdateutil.tz.tzlocal(). Was previously set by thetzlocallibrary. (breaking change)v0.8.0 (2016-10-31)Add comparison methods toZulu:is_beforeis_on_or_beforeis_afteris_on_or_afteris_betweenv0.7.3 (2016-10-24)OptimizeZulu()constructor by eliminating multiple unnecessary calls todatetimeconstructor.v0.7.2 (2016-09-06)FixZulunot being pickle-able.v0.7.1 (2016-08-22)Add missing magic method overrides forDeltafor+delta,-delta, andabs(delta)so thatDeltais returned instead ofdatetime.timedelta.__pos____neg____abs__v0.7.0 (2016-08-22)MakeZulu.__sub__andZulu.subtractreturn aDeltaobject instead ofdatetime.timedelta.Makezulu.deltaandZulu.Delta.parseaccept a number.Allow the first argument toZulu.shiftbe a timedelta or relative delta object.Ensure that mathematical magic methods forDeltareturnDeltaobjects and notdatetime.timedelta.__add____radd____sub____mul____rmul____floordiv____truediv__(Python 3 only)__div__(Python 2 only)__mod__(Python 3 only)__divmod__(Python 3 only)v0.6.0 (2016-08-14)Replace internal implementation of Unicode date pattern formatting with Babel’sformat_datetime.breaking changeRemove support for formatting to timestamp usingXandXX.breaking changeRename parse-from-timestamp token fromXtotimestamp.breaking changeAddzulu.createas factory function to create azulu.Zuluinstance.Add locale support toZulu.formatwhen using Unicode date pattern format tokens.Restore locale support toDelta.format.v0.5.0 (2016-08-13)Remove locale support fromDelta.format. Locale is currently not supported inZulu.formatso decided to disable it inDelta.formatuntil both can have it.breaking changev0.4.0 (2016-08-13)Renamezulu.DateTimetozulu.Zulu.breaking changeRenameZulu.isleaptoZulu.is_leap_year.breaking changeRemovezulu.formatalias (function can be accessed atzulu.parser.format_datetime).breaking changeRemoveZulu.leapdays.breaking changeAddZulu.days_in_month.Addzulu.Deltaclass that inherits fromdatetime.timedelta.Addzulu.deltaas alias tozulu.Delta.parse.AddZulu.time_from,Zulu.time_to,Zulu.time_from_now, andZulu.time_to_nowthat return “time ago” or “time to” humanized strings.Addzulu.rangeas alias toZulu.range.Addzulu.span_rangeas alias toZulu.span_range.Make time units (years, months, weeks, days, hours, minutes, seconds, microseconds) keyword arguments only forZulu.add/subtract, but allow positional argument to be an addable/subtractable object (datetime, timedelta, dateutil.relativedelta).breaking changev0.3.0 (2016-08-03)RenameDateTime.subtoDateTime.subtract.breaking changeAllow the first argument toDateTime.addto be adatetime.timedeltaordateutil.relativedeltaobject.Allow the first argument toDateTime.subtractto be aDateTime,datetime.datetime,datetime.timedelta, ordateutil.relativedeltaobject.Providezulu.ISO8601andzulu.TIMESTAMPas parse/format constants that can be used inzulu.parse(string, zulu.ISO8601)andDateTime.format(zulu.ISO8601).Remove special parse format string'timestamp'in favor of using just'X'as defined inzulu.TIMESTAMP.breaking changeImportzulu.parser.formattozulu.format.Fix bug inDateTimeaddition operation that resulted in a nativedatetimebeing returned instead ofDateTime.v0.2.0 (2016-08-02)AddDateTime.datetimeproperty that returns a native datetime.AddDateTime.fromgmtimethat creates aDateTimefrom a UTC basedtime.struct_time.AddDateTime.fromlocaltimethat creates aDateTimefrom a localtime.struct_time.AddDateTime.isleapmethod that returns whether its year is a leap year.AddDateTime.leapdaysthat calculates the number of leap days between its year and another year.AddDateTime.start_of/end_ofand other variants that return the start of end of a time frame:start/end_of_centurystart/end_of_decadestart/end_of_yearstart/end_of_monthstart/end_of_daystart/end_of_hourstart/end_of_minutestart/end_of_secondAddDateTime.spanthat returns the start and end of a time frame.AddDateTime.span_rangethat returns a range of spans.AddDateTime.rangethat returns a range of datetimes.AddDateTime.addandDateTime.submethods.Addyearsandmonthsarguments toDateTime.shift/add/sub.Drop support for milliseconds fromDateTime.shift/add/sub.breaking changeMakeDateTime.parse/formatunderstand a subset ofUnicode date patterns.Set defaults for year (1970), month (1), and day (1) arguments to newDateTimeobjects. Creating a newDateTimenow defaults to the start of the POSIX epoch.v0.1.2 (2016-07-26)Don’t pin install requirements to a specific version; use>=instead.v0.1.1 (2016-07-26)Fix bug inDateTime.naivethat resulted in aDateTimeobject being returned instead of a nativedatetime.v0.1.0 (2016-07-26)First release.MIT LicenseCopyright (c) 2020 Derrick GillandPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.