Skip to content

datetime module has no support for nanoseconds #59648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
goshawk mannequin opened this issue Jul 24, 2012 · 71 comments
Open

datetime module has no support for nanoseconds #59648

goshawk mannequin opened this issue Jul 24, 2012 · 71 comments
Assignees
Labels
extension-modules C modules in the Modules dir stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@goshawk
Copy link
Mannequin

goshawk mannequin commented Jul 24, 2012

BPO 15443
Nosy @malemburg, @tim-one, @mdickinson, @abalkin, @giampaolo, @bitdancer, @andyclegg, @gareth-rees, @eli-b, @serhiy-storchaka, @pganssle, @shlomoa
PRs
  • bpo-15443: Nanoseconds support for datetime objects (work in progress) #21987
  • Files
  • datetime.nanosecond.patch
  • datetime.nanosecond.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/abalkin'
    closed_at = None
    created_at = <Date 2012-07-24.19:36:50.070>
    labels = ['type-feature', 'library', '3.10']
    title = 'datetime module has no support for nanoseconds'
    updated_at = <Date 2021-12-18.16:09:10.349>
    user = 'https://bugs.python.org/goshawk'

    bugs.python.org fields:

    activity = <Date 2021-12-18.16:09:10.349>
    actor = 'gdr@garethrees.org'
    assignee = 'belopolsky'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2012-07-24.19:36:50.070>
    creator = 'goshawk'
    dependencies = []
    files = ['37509', '37512']
    hgrepos = []
    issue_num = 15443
    keywords = ['patch']
    message_count = 61.0
    messages = ['166326', '166331', '166333', '166335', '166336', '166338', '166340', '166345', '166361', '166364', '166383', '166385', '166386', '166387', '166414', '180125', '223039', '223042', '223066', '223068', '223071', '223073', '223074', '223075', '223077', '223078', '223080', '223082', '223083', '223106', '224360', '232952', '232962', '237338', '237807', '237809', '237819', '240243', '240244', '240290', '240291', '240292', '240294', '240299', '240398', '270266', '270535', '270885', '270886', '270887', '270888', '276748', '276749', '390474', '390479', '390483', '390486', '390491', '392382', '392418', '408859']
    nosy_count = 21.0
    nosy_names = ['lemburg', 'tim.peters', 'mark.dickinson', 'belopolsky', 'giampaolo.rodola', 'pythonhacker', 'Arfrever', 'r.david.murray', 'andrewclegg', 'python-dev', 'gdr@garethrees.org', 'Ramchandra Apte', 'Eli_B', 'serhiy.storchaka', 'goshawk', 'Niklas.Claesson', 'mdcb808@gmail.com', 'scoobydoo', 'tomikyos', 'p-ganssle', 'anglister']
    pr_nums = ['21987']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue15443'
    versions = ['Python 3.10']

    Linked PRs

    @goshawk
    Copy link
    Mannequin Author

    goshawk mannequin commented Jul 24, 2012

    As long as computers evolve time management becomes more precise and more granular.
    Unfortunately the standard datetime module is not able to deal with nanoseconds even if OSes are able to. For example if i do:

    print "%.9f" % time.time()
    1343158163.471209049

    I've actual timestamp from the epoch with nanosecond granularity.

    Thus support for nanoseconds in datetime would really be appreciated

    @goshawk goshawk mannequin added topic-ctypes type-feature A feature request or enhancement stdlib Python modules in the Lib dir and removed topic-ctypes labels Jul 24, 2012
    @malemburg
    Copy link
    Member

    Vincenzo Ampolo wrote:

    As long as computers evolve time management becomes more precise and more granular.
    Unfortunately the standard datetime module is not able to deal with nanoseconds even if OSes are able to. For example if i do:

    print "%.9f" % time.time()
    1343158163.471209049

    I've actual timestamp from the epoch with nanosecond granularity.

    Thus support for nanoseconds in datetime would really be appreciated

    I would be interested in an actual use case for this.

    @goshawk
    Copy link
    Mannequin Author

    goshawk mannequin commented Jul 24, 2012

    On 07/24/2012 01:28 PM, Marc-Andre Lemburg wrote:

    I would be interested in an actual use case for this.

    Alice has a dataset with nanosecond granularity. He wants to make a
    python library to let Bob access the dataset. Nowadays Alice has to
    implement her own time class losing all the flexibility of the datetime
    module. With this enhancement she can provide a library that just uses
    the standard python datetime module. Her library will get the needed
    time format, including nanoseconds.

    Many python sql libraries, like the one in django e the one in web2py,
    relay on datetime objects for time representation. Bob has a web2py
    website that has some data with nanosecond granularity. Nowadays Bob has
    to store this data as a string or a long number without the ability to
    use the powerful datetime module. With this enhancement Bob doesn't need
    to build or learn another interface, he can just use the datetime module
    using microseconds or nanoseconds as needed.

    Google search for "python datetime nanoseconds" shows more than 141k
    results:
    https://www.google.com/search?sourceid=chrome&ie=UTF-8&q=python+time#hl=en&biw=1615&bih=938&sclient=psy-ab&q=python+datetime+nanoseconds&oq=python+datetime+nanoseconds

    So this is definitively a requested feature. And as soon as technology
    evolves more people will ask for it.

    I imagine something like:

    import datetime
    nano_time = datetime.datetime(year=2012, month=07, day=24, hour=14,
    minute=35, second=3, microsecond=53, nanosecond=27)

    in case you need nanosecond granularity. if you don't need it just skip
    the nanosecond part and the module works like it's now. Of course
    strftime format should be updated to support nanoseconds.

    I can write a patch if some dev can maybe review it.

    Before someone takes the datetime source code and starts a third part
    module that supports nanoseconds, I think this enhancement has almost
    null impact in existing code and makes the datetime module even more
    powerful. It's up to the Cpython admins to decide between maintaining
    datetime module up to date with new needs or let third part modules take
    care of those lacks.

    Best Regards,

    Vincenzo Ampolo
    http://vincenzo-ampolo.net
    http://goshawknest.wordpress.com

    @bitdancer
    Copy link
    Member

    I believe Marc-Andre was looking for an actual real-world use case rather than a hypothetical one. We discussed this briefly on the irc channel and we think Guido vetoed it on a YAGNI basis (we haven't checked the archives though...) so a real world use case is probably required.

    @goshawk
    Copy link
    Mannequin Author

    goshawk mannequin commented Jul 24, 2012

    This is a real use case I'm working with that needs nanosecond precision
    and lead me in submitting this request:

    most OSes let users capture network packets (using tools like tcpdump or
    wireshark) and store them using file formats like pcap or pcap-ng. These
    formats include a timestamp for each of the captured packets, and this
    timestamp usually has nanosecond precision. The reason is that on
    gigabit and 10 gigabit networks the frame rate is so high that
    microsecond precision is not enough to tell two frames apart.
    pcap (and now pcap-ng) are extremely popular file formats, with millions
    of files stored around the world. Support for nanoseconds in datetime
    would make it possible to properly parse these files inside python to
    compute precise statistics, for example network delays or round trip times.

    Other case is in stock markets. In that field information is timed in
    nanoseconds and have the ability to easily deal with this kind of
    representation natively with datetime can make the standard module even
    more powerful.

    The company I work for is in the data networking field, and we use
    python extensively. Currently we rely on custom code to process
    timestamps, a nanosecond datetime would let us avoit that and use
    standard python datetime module.

    Best Regards,

    ---
    Vincenzo Ampolo
    http://vincenzo-ampolo.net
    http://goshawknest.wordpress.com

    @bitdancer
    Copy link
    Member

    Are the nanosecond timestamps timestamps or strings? If they are timestamps it's not immediately obvious why you want to convert them to datetime objects, so motivating that would probably help. On the other hand the fact that you have an application that does so is certain an argument for real world applicability.

    @bitdancer
    Copy link
    Member

    Even if accepted this can't get fixed in 2.7, so removing that from versions.

    @goshawk
    Copy link
    Mannequin Author

    goshawk mannequin commented Jul 25, 2012

    On 07/24/2012 04:20 PM, R. David Murray wrote:

    R. David Murray <rdmurray@bitdance.com> added the comment:

    Are the nanosecond timestamps timestamps or strings? If they are timestamps it's not immediately obvious why you want to convert them to datetime objects, so motivating that would probably help. On the other hand the fact that you have an application that does so is certain an argument for real world applicability.

    It depends. When they are exported for example as csv (this can be the
    case of market stock) or json (which is close to my case) that's a
    string so having a datetime object may be very helpful in doing datetime
    adds, subs, <, deltas and in changing representation to human readable
    format thanks to strftime() without loosing precison and maintaining
    readability.

    Think about a web application. User selects year, month, day, hour,
    minute, millisecond, nanosecond of an event and the javascript does a
    ajax call with time of this format (variant of iso8601):
    YYYY-MM-DDTHH:MM:SS.mmmmmmnnn (where nnn is the nanosecond representation).
    The python server takes that string, converts to a datetime, does all
    the math with its data and gives the output back using labeling data
    with int(nano_datetime.strftime('MMSSmmmmmmnnn')) so I've a sequence
    number that javascript can sort and handle easily.

    It's basically the same you already do nowadays at microseconds level,
    but this time you have to deal with nanosecond data.

    I agree with the YAGNI principle and I think that we have a clear
    evidence of a real use case here indeed.

    Best Regards

    @vstinner
    Copy link
    Member

    See the PEP-410.

    @malemburg
    Copy link
    Member

    Vincenzo Ampolo wrote:

    Vincenzo Ampolo <vincenzo.ampolo@gmail.com> added the comment:

    This is a real use case I'm working with that needs nanosecond precision
    and lead me in submitting this request:

    most OSes let users capture network packets (using tools like tcpdump or
    wireshark) and store them using file formats like pcap or pcap-ng. These
    formats include a timestamp for each of the captured packets, and this
    timestamp usually has nanosecond precision. The reason is that on
    gigabit and 10 gigabit networks the frame rate is so high that
    microsecond precision is not enough to tell two frames apart.
    pcap (and now pcap-ng) are extremely popular file formats, with millions
    of files stored around the world. Support for nanoseconds in datetime
    would make it possible to properly parse these files inside python to
    compute precise statistics, for example network delays or round trip times.

    Other case is in stock markets. In that field information is timed in
    nanoseconds and have the ability to easily deal with this kind of
    representation natively with datetime can make the standard module even
    more powerful.

    The company I work for is in the data networking field, and we use
    python extensively. Currently we rely on custom code to process
    timestamps, a nanosecond datetime would let us avoit that and use
    standard python datetime module.

    Thanks for the two use cases.

    You might want to look at mxDateTime and use that for your timestamps.
    It does provide full C double precision for the time part of a timestamp,
    which covers nanoseconds just fine.

    @abalkin
    Copy link
    Member

    abalkin commented Jul 25, 2012

    On Wed, Jul 25, 2012 at 4:17 AM, Marc-Andre Lemburg <report@bugs.python.org> wrote:

    ... full C double precision for the time part of a timestamp,
    which covers nanoseconds just fine.

    No, it does not:

    >>> import time
    >>> t = time.time()
    >>> t + 5e-9 == t
    True

    In fact, C double precision is barely enough to cover microseconds:

    >>> t + 1e-6 == t
    False
    
    >>> t + 1e-7 == t
    True

    @malemburg
    Copy link
    Member

    Alexander Belopolsky wrote:
    > 
    > Alexander Belopolsky <alexander.belopolsky@gmail.com> added the comment:
    > 
    > On Wed, Jul 25, 2012 at 4:17 AM, Marc-Andre Lemburg <report@bugs.python.org> wrote:
    >> ... full C double precision for the time part of a timestamp,
    >> which covers nanoseconds just fine.
    > 
    > No, it does not:
    > 
    >>>> import time
    >>>> t = time.time()
    >>>> t + 5e-9 == t
    > True
    > 
    > In fact, C double precision is barely enough to cover microseconds:
    > 
    >>>> t + 1e-6 == t
    > False
    > 
    >>>> t + 1e-7 == t
    > True

    I was referring to the use of a C double to store the time part
    in mxDateTime. mxDateTime uses the C double to store the number of
    seconds since midnight, so you don't run into the Unix ticks value
    range problem you showcased above.

    @malemburg
    Copy link
    Member

    Marc-Andre Lemburg wrote:
    > 
    >> Alexander Belopolsky <alexander.belopolsky@gmail.com> added the comment:
    >>
    >> On Wed, Jul 25, 2012 at 4:17 AM, Marc-Andre Lemburg <report@bugs.python.org> wrote:
    >>> ... full C double precision for the time part of a timestamp,
    >>> which covers nanoseconds just fine.
    >>
    >> No, it does not:
    >>
    >>>>> import time
    >>>>> t = time.time()
    >>>>> t + 5e-9 == t
    >> True
    >>
    >> In fact, C double precision is barely enough to cover microseconds:
    >>
    >>>>> t + 1e-6 == t
    >> False
    >>
    >>>>> t + 1e-7 == t
    >> True
    > 
    > I was referring to the use of a C double to store the time part
    > in mxDateTime. mxDateTime uses the C double to store the number of
    > seconds since midnight, so you don't run into the Unix ticks value
    > range problem you showcased above.

    There's enough room to even store 1/100th of a nanosecond, which may
    be needed for some physics experiments :-)

    False
    >>> x == x + 1e-10
    False
    >>> x == x + 1e-11
    False
    >>> x == x + 1e-12
    True

    @malemburg
    Copy link
    Member

    [Roundup's email interface again...]

    >>> x = 86400.0
    >>> x == x + 1e-9
    False
    >>> x == x + 1e-10
    False
    >>> x == x + 1e-11
    False
    >>> x == x + 1e-12
    True

    @goshawk
    Copy link
    Mannequin Author

    goshawk mannequin commented Jul 25, 2012

    Have a look to this python dev mailing list thread too:

    http://mail.python.org/pipermail/python-dev/2012-July/121123.html

    @andyclegg
    Copy link
    Mannequin

    andyclegg mannequin commented Jan 17, 2013

    I would like to add a real-world use case I have for nanosecond-precision support. I deal with data loggers that are controlled by GPS clocks, and I am writing some processing software in Python that requires the input of high-precision timestamps for calculating clock drifts and offsets. The addition of nanosecond-precision support in datetime would allow me to use this rather than a homebrew solution.

    @NiklasClaesson
    Copy link
    Mannequin

    NiklasClaesson mannequin commented Jul 14, 2014

    I would like to add a use case. Control systems for particle accelerators. We have ns, sometimes ps precision on timestamped data acquisitions and we would like to use Python to do calculations.

    @abalkin
    Copy link
    Member

    abalkin commented Jul 14, 2014

    Given that struct timespec defined as

               struct timespec {
                   time_t   tv_sec;        /* seconds */
                   long     tv_nsec;       /* nanoseconds */
               };

    is slowly becoming the prevailing standard to represent time in system interfaces, Python's inability to faithfully store it in a high level object will increasingly become a handicap.

    People are starting to put nanoseconds in their databases not because they really need such precision, but because this is what they get from their devices and at the collection time cannot do anything "smart".

    The program that collects the events may simply not have time to do anything other than store raw data, or not have the higher level knowledge of what is the proper rounding.

    The proper rounding is best to be done at the analysis time and by a program written in a higher level language such as Python.

    @abalkin abalkin self-assigned this Jul 14, 2014
    @pitrou
    Copy link
    Member

    pitrou commented Jul 14, 2014

    For the record, numpy's datetime and timedelta types have theoretical support for attoseconds.

    @abalkin
    Copy link
    Member

    abalkin commented Jul 15, 2014

    numpy's datetime64 and timedelta64 types are so utterly broken that I would only recommend studying them as a negative example of how not to design a date-time library.

    @tim-one
    Copy link
    Member

    tim-one commented Jul 15, 2014

    A note from Guido, from about 2 years ago:

    https://mail.python.org/pipermail/python-dev/2012-July/121127.html

    """
    TBH, I think that adding nanosecond precision to the datetime type is
    not unthinkable. You'll have to come up with some clever backward
    compatibility in the API though, and that will probably be a bit ugly
    (you'd have a microsecond parameter with a range of 0-1000000 and a
    nanosecond parameter with a range of 0-1000). Also the space it takes
    in memory would probably increase (there's no room for an extra 10
    bits in the carefully arranged 8-byte internal representation).
    """

    Add pickle, etc.

    @abalkin
    Copy link
    Member

    abalkin commented Jul 15, 2014

    (there's no room for an extra 10 bits in the
    carefully arranged 8-byte internal representation)

    According to a comment on top of Include/datetime.h, the internal representation of datetime is 10, not 8 bytes.

    /* Fields are packed into successive bytes, each viewed as unsigned and

    • big-endian, unless otherwise noted:
    • byte offset
    • 0 year 2 bytes, 1-9999
    • 2 month 1 byte, 1-12
    • 3 day 1 byte, 1-31
    • 4 hour 1 byte, 0-23
    • 5 minute 1 byte, 0-59
    • 6 second 1 byte, 0-59
    • 7 usecond 3 bytes, 0-999999
    • 10
      */

    (if you don't trust the comments check the definitions a few lines below)

    #define _PyDateTime_DATETIME_DATASIZE 10

    AFAIK, Python objects are allocated with at least 32-bit alignment, so we have at least 2 unused bytes at the end of each datetime object.

    Furthermore, out of 24 bits allocated for microseconds, only 20 are used, so nanoseconds can be accommodated by adding a single byte to DATETIME_DATASIZE.

    @pitrou
    Copy link
    Member

    pitrou commented Jul 15, 2014

    Le 14/07/2014 21:37, Alexander Belopolsky a écrit :

    AFAIK, Python objects are allocated with at least 32-bit alignment,

    64 bits, actually, when using obmalloc.c.

    @tim-one
    Copy link
    Member

    tim-one commented Jul 15, 2014

    Yup, it's definitely more than 8 bytes. In addition to the comments you quoted, an in-memory datetime object also has a full Python object header, a member to cache the hash code, and a byte devoted to saying whether or not a tzinfo member is present.

    Guessing Guido was actually thinking about the pickle size - but that's 10 bytes (for a "naive" datetime object).

    @abalkin
    Copy link
    Member

    abalkin commented Jul 15, 2014

    Guessing Guido was actually thinking about the pickle size

    No, pickle also comes with an overhead

    >>> from datetime import *
    >>> import pickle
    >>> t = datetime.now()
    >>> len(pickle.dumps(t))
    70

    For the present discussion, DATETIME_DATASIZE is the only relevant number because we are not going to change anything other than the payload layout in the datetime object or its pickle serialization.

    @abalkin
    Copy link
    Member

    abalkin commented Apr 7, 2021

    @pganssle - let's keep the substantive discussions in the tracker so that they are not lost on github. You wrote:

    """
    what is still blocking / needs to be done on this? Beta freeze for Python 3.10 is coming up at the beginning of May and I think we may have enough time to get this in before then. Probably would have been better to get it into an alpha release, but if we miss beta freeze it'll get pushed to 3.11, and I do think that nanosecond support is a desirable feature for a lot of people.

    It might be good for us to get an explicit "to-do" list of concerns to be addressed before this can be merged.
    """

    I don't think full nanosecond support is feasible to complete in the remaining weeks, but we can try to add nanoseconds to timedelta only. The mixed datetime + timedelta ops will still truncate, but many time-related operations will be enabled.

    I would even argue that when nanoseconds precision is required, it is more often intervals no longer than a few days and rarely a specific point in time.

    @abalkin abalkin added 3.10 only security fixes and removed 3.7 (EOL) end of life labels Apr 7, 2021
    @pganssle
    Copy link
    Member

    pganssle commented Apr 7, 2021

    I don't think full nanosecond support is feasible to complete in the remaining weeks

    This may be so, but I think the important part of that question is "what work needs to be done and what questions need to be answered?" If the answer is that we need to make 3 decisions and do the C implementation, that seems feasible to do in under a month. If the answer is that we've got 10 contentious UI issues and we probably want to go through the PEP process, I agree with your assessment of the timing. Regardless, we'll need to know what work needs to be done before we do it...

    but we can try to add nanoseconds to timedelta only. The mixed datetime + timedelta ops will still truncate, but many time-related operations will be enabled. I would even argue that when nanoseconds precision is required, it is more often intervals no longer than a few days and rarely a specific point in time.

    To be honest, I don't find this very compelling and I think it will only confuse people. I think most people use timedelta to represent something you add or subtract to a datetime. Having the nanoseconds part of it truncate seems like it would be frustrating and counter-intuitive.

    From the use cases in this thread:

    So I don't think there's high enough demand for nanosecond-timedelta on its own that we need to rush it out there before datetime gets it.

    @abalkin
    Copy link
    Member

    abalkin commented Apr 7, 2021

    Is there high enough demand for nanoseconds in datetime and time instances?

    How often nanosecond timestamps contain anything other than 0s or garbage in the last three digits?

    In my experience, all people want to do with such timestamps is to convert them to something expressed in hours, minutes and seconds rather than just a huge number of seconds and back without loosing the value.

    A timedelta is almost always a decent replacement for either datetime or time in those cases and sometimes it is even preferable because arithmetically it is closer to numbers.

    @mdcb808gmailcom
    Copy link
    Mannequin

    mdcb808gmailcom mannequin commented Apr 7, 2021

    This brings me back some times. Sorry if I am not up to date, the issue as I recall from back then was there wasn't even microseconds.
    In telemetry, you can often have these kind time stamped measurements, it's not insignificant noise nobody cares about.

    @abalkin
    Copy link
    Member

    abalkin commented Apr 7, 2021

    In telemetry,

    a nanosecond often translates to about a foot and 5 hours gets you to Pluto. Telemetry is exactly an application where absolute timestamps rarely make any sense.

    @mdcb808gmailcom
    Copy link
    Mannequin

    mdcb808gmailcom mannequin commented Apr 30, 2021

    In the confines of PTP / IEEE1588, it's actually quite common and can be useful. It's not so much the ns, but the <1us that is missing.

    @mdickinson
    Copy link
    Member

    [Alexander]

    Is there high enough demand for nanoseconds in datetime and time instances?

    One need that we've encountered in real code is simply for compatibility. We have Python code that interacts with a logging web service whose timestamps include nanosecond information. Whether or not nanosecond resolution makes sense for those timestamps is a moot point: that's out of our control.

    When representing information retrieved from that web service in Python-land, we have a problem. If datetime.datetime had nanosecond precision, then using datetime.datetime to represent the retrieved values would be a no-brainer. As it is, we face a choice between:

    • truncating or rounding to microsecond precision, and losing information as a result (which is particularly problematic if we want to write records back at any point)
    • representing in some indirect form (as a str, an integer number of nanoseconds, a (datetime, nanoseconds) tuple, ...) and requiring the user to convert values for plotting or other analysis
    • writing our own non-standard ns-supporting datetime class, or looking for a 3rd party library with that support

    None of those choices are terrible, but none of them are particularly palatable compared with using a standard library solution. (FWIW, we went with option 2, returning nanoseconds since the Unix epoch as an int.)

    @gareth-rees
    Copy link
    Mannequin

    gareth-rees mannequin commented Dec 18, 2021

    I also have a use case that would benefit from nanosecond resolution in Python's datetime objects, that is, representing and querying the results of clock_gettime() in a program trace.

    On modern Linuxes with a vDSO, clock_gettime() does not require a system call and completes within a few nanoseconds. So Python's datetime objects do not have sufficient resolution to distinguish between adjacent calls to clock_gettime().

    This means that, like Mark Dickinson above, I have to choose between using datetime for queries (which would be convenient) and accepting that nearby events in the trace may be indistinguishable, or implementing my own datetime-like data structure.

    @fenchu
    Copy link

    fenchu commented Jan 5, 2023

    More than 10 years have this been open. :-)

    strptime should be able to parse it, please harmonize strftime from other implementations with python strptime:
    My major problem is that porting data between Go, Java, .NET and python may change the timestamp output slightly
    (6digit rounding)

    Most of our rest-apis (500+) are Java spring-boot 7 digits, Go (9digits on linux and 7digits on windows)
    (Also .NET have 7 to 9 digits and sqlserver,oracle and db2 dumps 9 digits if needed)

    I do this this conversion almost daily:

    >>> t = '2023-01-05T09:45:41.0877981+01:00' # this example taken from K6 json output: https://k6.io/docs/results-output/real-time/json/ a Go commercial program
    >>> datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S.%f%z")                                   
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Program Files\Python310\lib\_strptime.py", line 568, in _strptime_datetime
        tt, fraction, gmtoff_fraction = _strptime(data_string, format)
      File "C:\Program Files\Python310\lib\_strptime.py", line 349, in _strptime
        raise ValueError("time data %r does not match format %r" %
    ValueError: time data '2023-01-05T09:45:41.0877981+01:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
    >>> t1 = t[:-7] + t[-6:]
    >>> datetime.datetime.strptime(t1, "%Y-%m-%dT%H:%M:%S.%f%z") 
    datetime.datetime(2023, 1, 5, 9, 45, 41, 87798, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))

    @bfsoares
    Copy link

    More than 10 years have this been open. :-)

    strptime should be able to parse it, please harmonize strftime from other implementations with python strptime: My major problem is that porting data between Go, Java, .NET and python may change the timestamp output slightly (6digit rounding)

    Most of our rest-apis (500+) are Java spring-boot 7 digits, Go (9digits on linux and 7digits on windows) (Also .NET have 7 to 9 digits and sqlserver,oracle and db2 dumps 9 digits if needed)

    I do this this conversion almost daily:

    >>> t = '2023-01-05T09:45:41.0877981+01:00' # this example taken from K6 json output: https://k6.io/docs/results-output/real-time/json/ a Go commercial program
    >>> datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S.%f%z")                                   
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Program Files\Python310\lib\_strptime.py", line 568, in _strptime_datetime
        tt, fraction, gmtoff_fraction = _strptime(data_string, format)
      File "C:\Program Files\Python310\lib\_strptime.py", line 349, in _strptime
        raise ValueError("time data %r does not match format %r" %
    ValueError: time data '2023-01-05T09:45:41.0877981+01:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
    >>> t1 = t[:-7] + t[-6:]
    >>> datetime.datetime.strptime(t1, "%Y-%m-%dT%H:%M:%S.%f%z") 
    datetime.datetime(2023, 1, 5, 9, 45, 41, 87798, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))
    

    I have this same problem. I changed _strptime.py file in lines 188 and 424, to include format n for nanoseconds (1 until 9 digits):

    Aproximately line 188 :
    'f': r"(?P[0-9]{1,6})",
    'n': r"(?P[0-9]{1,9})", #New format included
    'H': r"(?P2[0-3]|[0-1]\d|\d)",

    Aproximately line 424:

    elif group_key == 'f':
    s = found_dict['f']
    # Pad to always return microseconds.
    s += "0" * (6 - len(s))
    fraction = int(s)
    elif group_key == 'n': #New format included
    s = found_dict['n']
    # Pad to always return nanoseconds.
    s += "0" * (9 - len(s))
    fraction = int(round(int(s)/1000, 0))

    elif group_key == 'A':

    I´ll aprecciate if someone could update _srtptime.py with this improvements.

    @adivekar-utexas
    Copy link

    adivekar-utexas commented Mar 25, 2023

    I also have the same problem. My use-case is a generic Timer I am implementing for profiling data-processing code for high-performance Machine Learning modeling.

    This is purely in Python.

    time.perf_counter_ns() gives me a relative time in nanoseconds, and I can get the time diff as follows:

    start: int = time.perf_counter_ns()
    ...  ## Do something 
    end: int = time.perf_counter_ns()
    

    For certain use-cases a piece of code runs very fast (few hundred nanoseconds) but needs to run hundreds of billions of times, example dict lookup when deduplicating Amazon product embeddings.

    So, timing it effectively is useful.

    It's annoying that I can't just use timedelta(nanoseconds=end-start) to get the difference in nanoseconds, since this gets rounded to either timedelta(microseconds=0) or timedelta(microseconds=1).

    I feel this could be implemented really easily in timedelta? That would make it compatible with time.perf_counter_ns()

    @douglas-raillard-arm
    Copy link

    Another use case: polars is currently using datetime.timedelta() objects to represent values of the Duration('ns') dtype. This allows avoiding re-inventing the wheel in all Python processing exploiting the value, but unfortunately the lack of nanosecond in timedelta() means it's a destructive operation:
    pola-rs/polars#14695

    This is a situation that seems similar to @mdickinson where using the std lib would be a no-brainer if it did the job, but unfortunately it does not here and there isn't any great solution, especially if this is part of the public API of a library.

    @nineteendo
    Copy link
    Contributor

    nineteendo commented Jun 20, 2024

    Would this be a potential solution?

    import datetime
    from datetime import time
    from operator import index
    from typing import overload
    
    class Time(time):
        @overload
        def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0): ...
        @overload
        def __new__(cls, hour=0, minute=0, second=0, microsecond=0, nanosecond=0, tzinfo=None, *, fold=0): ...
    
        def __new__(cls, hour=0, minute=0, second=0, microsecond=0, nanosecond=0, tzinfo=None, *, fold=0):
            if (nanosecond is None or isinstance(nanosecond, datetime.tzinfo)) and tzinfo is None:
                # Make constructor backwards compatible
                nanosecond, tzinfo = 0, nanosecond
                
            nanosecond = index(nanosecond)
            if not 0 <= nanosecond <= 999:
                raise ValueError('nanosecond must be in 0..999', nanosecond)
    
            self = super().__new__(cls, hour, minute, second, microsecond, tzinfo, fold=fold)
            self._nanosecond = nanosecond
            return self
    
        @property
        def nanosecond(self):
            """nanosecond (0-999)"""
            return self._nanosecond

    Note

    This currently doesn't raise an error:

    t = Time(nanosecond=None)

    Is it worth it to do the parsing manually, or is a warning of the type checker good enough?

    @nineteendo
    Copy link
    Contributor

    nineteendo commented Jun 20, 2024

    Sadly passing the extra arguments of timedelta() positionally would have to be deprecated if we want the intuitive format:

    class timedelta:
        if sys.version_info >= (3, 16):
            def __new__(days=0, seconds=0, microseconds=0, nanoseconds=0, *, weeks=0, hours=0, minutes=0, milliseconds=0): ...
        elif sys.version_info >= (3, 14):
            def __new__(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0, *, nanoseconds=0): ...
        else:
            def __new__(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0): ...

    @nineteendo
    Copy link
    Contributor

    @vstinner, do you think this approach is reasonable?

    @vstinner
    Copy link
    Member

    @vstinner, do you think this approach is reasonable?

    Changing the signature in Python 3.16 to put nanoseconds instead of milliseconds is a bad idea. I don't think that positional arguments can ever change in the datetime API.

    @nineteendo
    Copy link
    Contributor

    nineteendo commented Jun 20, 2024

    Yeah, that would break >1.1k files without raising an error: /timedelta\(\w+, \w+, \w+, \w+/.

    Let's only do it for datetime.datetime and datetime.time then, as we can make that fully backwards compatible.
    We could decide to deprecate passing tzinfo positionally without nanosecond though as it's a bit ugly to maintain.

    @Eclips4 Eclips4 removed the 3.10 only security fixes label Aug 11, 2024
    @JakkuSakura
    Copy link

    It seems like it's not going to be solved soon. Check out the whenever library, which has nanosecond support. Unfortunately for database applications, some workarounds/hacks are needed

    @encukou encukou added the extension-modules C modules in the Modules dir label Mar 17, 2025
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    extension-modules C modules in the Modules dir stdlib Python modules in the Lib dir type-feature A feature request or enhancement
    Projects
    Development

    No branches or pull requests