Skip to content

datetime needs an "epoch" method #46988

Closed

Description

@tebeka
mannequin
BPO 2736
Nosy @malemburg, @tim-one, @jribbens, @amauryfa, @mdickinson, @abalkin, @pitrou, @catlee, @vstinner, @bitdancer
Files
  • add-datetime-totimestamp-method.diff: Implementation of datetime.datetime.timetuple and tests.
  • add-datetime-totimestamp-method-docs.diff
  • datetime_totimestamp-3.patch
  • issue2736-doc.diff
  • 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 = <Date 2011-04-25.17:03:30.218>
    created_at = <Date 2008-05-01.21:03:25.299>
    labels = ['type-feature', 'docs']
    title = 'datetime needs an "epoch" method'
    updated_at = <Date 2012-06-08.16:41:09.959>
    user = 'https://github.com/tebeka'

    bugs.python.org fields:

    activity = <Date 2012-06-08.16:41:09.959>
    actor = 'belopolsky'
    assignee = 'belopolsky'
    closed = True
    closed_date = <Date 2011-04-25.17:03:30.218>
    closer = 'belopolsky'
    components = ['Documentation']
    creation = <Date 2008-05-01.21:03:25.299>
    creator = 'tebeka'
    dependencies = []
    files = ['10251', '10256', '12329', '21565']
    hgrepos = []
    issue_num = 2736
    keywords = ['patch']
    message_count = 67.0
    messages = ['66045', '66140', '66532', '66539', '66601', '66610', '75723', '75899', '75900', '75902', '75903', '75904', '75912', '76003', '76324', '76327', '76329', '76331', '76332', '76340', '76344', '76345', '76351', '76352', '77650', '77651', '99545', '103875', '106229', '106230', '106249', '106251', '106252', '106254', '106255', '124197', '124203', '124204', '124225', '124230', '124231', '124237', '124245', '124248', '124252', '124255', '124256', '124257', '124259', '132695', '132697', '132818', '132977', '132994', '133008', '133009', '133011', '133037', '133039', '133053', '133056', '133058', '133072', '133207', '133245', '134395', '162533']
    nosy_count = 23.0
    nosy_names = ['lemburg', 'tim.peters', 'ping', 'jribbens', 'guettli', 'amaury.forgeotdarc', 'mark.dickinson', 'davidfraser', 'belopolsky', 'pitrou', 'andersjm', 'catlee', 'vstinner', 'tomster', 'werneck', 'hodgestar', 'Neil Muller', 'erik.stephens', 'steve.roberts', 'r.david.murray', 'vivanov', 'python-dev', 'Jay.Taylor']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue2736'
    versions = ['Python 3.3']

    Activity

    1. tebeka commented on May 1, 2008

      tebekamannequin
      MannequinAuthor

      If you try to convert datetime objects to seconds since epoch and back
      it will not work since the microseconds get lost:

      >>> dt = datetime(2008, 5, 1, 13, 35, 41, 567777)
      >>> seconds = mktime(dt.timetuple())
      >>> datetime.fromtimestamp(seconds) == dt
      False
      
      Current fix is to do
      >>> seconds += (dt.microsecond / 1000000.0)
      >>> datetime.fromtimestamp(seconds) == dt
      True
    2. added
      type-bugAn unexpected behavior, bug, or error
      stdlibStandard Library Python modules in the Lib/ directory
      on May 1, 2008
    3. werneck commented on May 3, 2008

      werneckmannequin
      Mannequin

      That's expected as mktime is just a thin wrapper over libc mktime() and
      it does not expect microseconds. Changing time.mktime doesn't seems an
      option, so the best alternative is to implement a method in datetime
      type. Is there a real demand for C code implementing this to justify it?

    4. hodgestar commented on May 10, 2008

      hodgestarmannequin
      Mannequin

      Attached a patch which adds a .totimetuple(...) method to
      datetime.datetime and tests for it.

      The intention is that the dt.totimetuple(...) method is equivalent to:
      mktime(dt.timetuple()) + (dt.microsecond / 1000000.0)

    5. hodgestar commented on May 10, 2008

      hodgestarmannequin
      Mannequin

      Patch adding documentation for datetime.totimestamp(...).

    6. tebeka commented on May 11, 2008

      tebekamannequin
      MannequinAuthor

      I think the name is not good, should be "toepoch" or something like that.

    7. NeilMuller commented on May 11, 2008

      NeilMullermannequin
      Mannequin

      datetime has fromtimestamp already, so using totimestamp keeps naming
      consistency (see toordinal and fromordinal).

    8. vstinner commented on Nov 11, 2008

      @vstinner
      Member

      See also bpo-1673409

    9. vstinner commented on Nov 15, 2008

      @vstinner
      Member

      I like the method, but I have some comments about the new method:

      • datetime_totimestamp() is not well indented
      • "PyObject *time" should be defined at the before the first
        instruction
      • why not using "if (time == NULL) return NULL;" directly instead of
        using a block in case of time is not NULL?
      • there are reference leaks: timetuple, timestamp and
        PyFloat_FromDouble()

      I wrote a similar patch before reading
      add-datetime-totimestamp-method.diff which does exactly the same... I
      attach my patch but both should be merged.

    10. vstinner commented on Nov 15, 2008

      @vstinner
      Member

      Here is a merged patch of the three patches. Except the C
      implementation of datetime_totimestamp() (written by me), all code is
      written by hodgestar.

    11. abalkin commented on Nov 15, 2008

      @abalkin
      Member

      I would like to voice my opposition the totimestamp method.

      Representing time as a float is a really bad idea (originated at
      Microsoft as I have heard). In addition to the usual numeric problems
      when dealing with the floating point, the resolution of the floating
      point timestamp varies from year to year making it impossible to
      represent high resolution historical data.

      In my opinion both time.time() returning float and
      datetime.fromtimestamp() taking a float are both design mistakes and
      adding totimestamp that produces a float will further promote a bad
      practice.

      I would not mind integer based to/from timestamp methods taking and
      producing seconds or even (second, microsecond) tuples, but I don't
      think changing fromtimestamp behavior is an option.

    12. vstinner commented on Nov 15, 2008

      @vstinner
      Member

      Le Saturday 15 November 2008 02:15:30 Alexander Belopolsky, vous avez écrit :

      I don't think changing fromtimestamp behavior is an option.

      It's too late to break the API (Python3 is in RC stage ;-)), but we can create
      new methods like:
      datetime.fromepoch(seconds, microseconds=0) # (int/long, int)
      datetime.toepoch() -> (seconds, microseconds) # (int/long, int)

    13. abalkin commented on Nov 15, 2008

      @abalkin
      Member

      On Fri, Nov 14, 2008 at 8:37 PM, STINNER Victor <report@bugs.python.org> wrote:

      .. but we can create new methods like:
      datetime.fromepoch(seconds, microseconds=0) # (int/long, int)

      While 1970 is the most popular epoch, I've seen 1900, 2000 and even
      2035 (!) being used as well. Similarly, nanoseconds are used in high
      resolution time sources at least as often as microseconds. This makes
      fromepoch() ambiguous and it is really unnecessary because it can be
      written as epoch + timedelta(0, seconds, microseconds).

      datetime.toepoch() -> (seconds, microseconds) # (int/long, int)

      I would much rather have divmod implemented as you suggested in
      bpo-2706 . Then toepoch is simply

      def toepoch(d):
          x, y = divmod(d, timedellta(0, 1))
          return x, y.microseconds
    14. vstinner commented on Nov 15, 2008

      @vstinner
      Member

      Le Saturday 15 November 2008 04:17:50 Alexander Belopolsky, vous avez écrit :

      it is really unnecessary because it can be
      written as epoch + timedelta(0, seconds, microseconds).

      I tried yesterday and it doesn't work!

      datetime.datetime(1970, 1, 1, 1, 0)
      >>> t1 = epoch + timedelta(seconds=-1660000000)
      >>> t2 = datetime.fromtimestamp(-1660000000)
      >>> t2
      datetime.datetime(1917, 5, 26, 1, 53, 20)
      >>> t1 - t2
      datetime.timedelta(0)
      >>> t2 = datetime.fromtimestamp(-1670000000)
      >>> t2
      datetime.datetime(1917, 1, 30, 7, 6, 40)
      >>> t1 = epoch + timedelta(seconds=-1670000000)
      >>> t1 - t2
      datetime.timedelta(0, 3600)

      We lost an hour durint the 1st World War :-)

      Whereas my implementation using mktime() works:

      -1670000000.0

    15. 47 remaining items

    16. malemburg commented on Apr 5, 2011

      @malemburg
      Member

      STINNER Victor wrote:

      STINNER Victor <victor.stinner@haypocalc.com> added the comment:

      Marc, could you maybe write a new patching taking care of the DST and
      maybe also the timezone? It looks like you have a long experience in
      timestamps :-)

      Sorry, but no. I'm not really a fan of the datetime module and
      try to stay away from it whenever I can :-)

      Note that dealing with DST in timezones other than the local time
      zone, is bound to go wrong without direct access to the tz library.
      The C lib doesn't provide any good way to access timezone
      information other than the local timezone or UTC.

      When dealing with date/time values, it is usually best to stay with
      UTC and only transform those values into local times in user
      interfaces on the front-end client.

      Consequently, I'd suggest to only allow UTC and local timezone
      conversions for the method in the datetime module.

    17. abalkin commented on Apr 5, 2011

      @abalkin
      Member

      On Tue, Apr 5, 2011 at 4:33 AM, Marc-Andre Lemburg
      <report@bugs.python.org> wrote:
      ..

      mxDateTime, which in large parts inspired the Python datetime module,
      has had a .ticks() method (for local time) and a .gmticks() method
      (for UTC) for more than a decade now

      Yes, mxDateTime's gmticks()/ticks() pair of functions present a much
      more mature design than anything that has been proposed here. It is
      telling, however, that no one has mentioned mxDateTime's gmticks() on
      this issue in four years. On a duplicate bpo-1673409, Marc did
      bring it up, but as far as I can tell, no one responded. See
      msg75411.

      Google code search,

      http://www.google.com/codesearch?hl=en&sa=N&q=gmticks+lang:python

      returns only 13 hits for "gmticks". In several instances, the
      resulting float is immediately converted to int, in other instances
      "gmticks" is mentioned in comments and the code works around its bugs.

      I would not use Google Code search as an ultimate arbiter on the
      popularity of a feature, so I would really like to hear from the
      proponents about real life uses of gmticks() or any other examples
      where a similar method "has been reimplemented over and over again."

      so far, I haven't seen a single complaint about any of the issues raised in this discussion.

      Well, search for gmticks does not return too many hits outside of
      mxDateTime code and manuals, but I had no trouble finding this:

      """
      okay, all the MySQLdb dataobject tick-based time handling methods are
      broken in various ways -- reconstruct GMT ticks from time module's
      mktime...
      """
      http://viewvc.tigris.org/ds/viewMessage.do?dsForumId=4251&dsMessageId=656863

      Follow the link for some more colorful language describing developer's
      experience with the feature.

      Note that it is likely that the bug MySQLdb developer complained about
      was fixed in mxDateTime at some point,
      <http://www.egenix.com/www2002/python/mxDateTime-History.html\>, but
      this shows that implementing gmticks() correctly is not as trivial as
      those who never tried might think.

      The methods naturally return the Unix ticks value as float,
      since that's what the time module uses as basis

      Which in turn is a mistake IMO. Note that POSIX does not use float
      timestamps for a reason.

      and the whole purpose
      of those methods is to make interaction with the time module easy
      and straight-forward.

      This is not the goal that I would support. I would rather see code
      that uses datetime module not require time module methods at all.

      Victor's patch could easily be updated to return floats as well,
      to make it compatible with the time module.

      Victor reported implementing two methods, one to return a float and
      another to return a tuple. See msg124259. I am not sure I've seen
      that code.

      There's only one catch that Victor's patch doesn't include ...

      No, it is not about "only one catch". Victor's patch is simply wrong.
      For an aware datetime instance it extracts DST flag from tzinfo, but
      ignores the offset.

    18. abalkin commented on Apr 5, 2011

      @abalkin
      Member

      MAL> Since most of the datetime module was inspired by mxDateTime,
      MAL> I wonder why [ticks()/gmticks()] were left out. (msg75411)

      """
      The datetime module intended to be an island of relative sanity.
      Because the range of dates "timestamps" can represent varies across
      platforms (and even "the epoch" varies), datetime doesn't even try to
      produce timestamps directly -- datetime is more of an alternative to
      "seconds from the epoch" schemes. Because datetime objects have
      greater range and precision than timestamps, conversion is
      problem-free in only one direction. It's not a coincidence that
      that's the only direction datetime supplies ;-)
      """ - Tim Peters

      http://bytes.com/topic/python/answers/522572-datetime-timestamp

      I will also add that fromtimestamp() is not invertible in the presence of DST. That's why mxDatetime.ticks() takes a DST flag making it effectively a multi-valued function. Note that naive users, who just want to pass datetime values to an OS function expecting a float, most likely will not have means of properly obtaining DST flag.

    19. malemburg commented on Apr 5, 2011

      @malemburg
      Member

      Alexander Belopolsky wrote:

      Alexander Belopolsky <belopolsky@users.sourceforge.net> added the comment:

      On Tue, Apr 5, 2011 at 4:33 AM, Marc-Andre Lemburg
      <report@bugs.python.org> wrote:
      ..
      > mxDateTime, which in large parts inspired the Python datetime module,
      > has had a .ticks() method (for local time) and a .gmticks() method
      > (for UTC) for more than a decade now

      Yes, mxDateTime's gmticks()/ticks() pair of functions present a much
      more mature design than anything that has been proposed here. It is
      telling, however, that no one has mentioned mxDateTime's gmticks() on
      this issue in four years. On a duplicate bpo-1673409, Marc did
      bring it up, but as far as I can tell, no one responded. See
      msg75411.

      Google code search,

      http://www.google.com/codesearch?hl=en&sa=N&q=gmticks+lang:python

      returns only 13 hits for "gmticks". In several instances, the
      resulting float is immediately converted to int, in other instances
      "gmticks" is mentioned in comments and the code works around its bugs.

      I would not use Google Code search as an ultimate arbiter on the
      popularity of a feature, so I would really like to hear from the
      proponents about real life uses of gmticks() or any other examples
      where a similar method "has been reimplemented over and over again."

      mxDateTime needs those two methods, since it doesn't natively
      use timezones. The .ticks() method is used for local time values,
      .gmticks() for UTC ones; that's why there are two methods.

      The .gmticks() method is always used when storing UTC values
      in mxDateTime instances, which actually is the preferred way
      of storing data in databases. Google Code doesn't really count
      much, since it only scans a limited number of OSS code bases.
      Most of our users are commercial users who use the tools
      in-house.

      Note that implementing .gmticks() is fairly easy on POSIX
      conform systems. On most others, timegm() can be used. If
      that doesn't exist, things get tricky, but that case should
      be rare nowadays.

      > so far, I haven't seen a single complaint about any of the issues raised in this discussion.

      Well, search for gmticks does not return too many hits outside of
      mxDateTime code and manuals, but I had no trouble finding this:

      """
      okay, all the MySQLdb dataobject tick-based time handling methods are
      broken in various ways -- reconstruct GMT ticks from time module's
      mktime...
      """
      http://viewvc.tigris.org/ds/viewMessage.do?dsForumId=4251&dsMessageId=656863

      Follow the link for some more colorful language describing developer's
      experience with the feature.

      Note that it is likely that the bug MySQLdb developer complained about
      was fixed in mxDateTime at some point,
      <http://www.egenix.com/www2002/python/mxDateTime-History.html\>, but
      this shows that implementing gmticks() correctly is not as trivial as
      those who never tried might think.

      Note that he was referring to the .ticks() method, not the .gmticks()
      method. The patch doesn't say which version of mxDateTime he was
      using. The bug mentioned in the changelog was fixed in 1998. It is
      possible, however, that the mktime() on his system was broken - which
      is why I added a test for it in mxDateTime.

      >
      > The methods naturally return the Unix ticks value as float,
      > since that's what the time module uses as basis

      Which in turn is a mistake IMO. Note that POSIX does not use float
      timestamps for a reason.

      The time module is our reference in this case and this tries hard
      to add fractions of a second to the value :-)

      Note that sub-second accuracy relies on a number of factors,
      the storage format most certainly is the least important
      aspect ;-)

      On many systems, you only get 1/100s accuracy, on others, the timer
      ticks in fixed increments, giving you even weirder sub-second values
      (e.g. time appears to stay constant between time.time() calls).

      OTOH, there's a new set of APIs for nano-second accuracy available
      now, which the datetime module objects cannot represent at all due
      to the integer-based storage format.

      BTW: The integer format was chose in order to keep the memory
      footprint of the objects low.

      > and the whole purpose
      > of those methods is to make interaction with the time module easy
      > and straight-forward.

      This is not the goal that I would support. I would rather see code
      that uses datetime module not require time module methods at all.

      No chance :-) In practice, the time module gets used a lot
      for date/time storage or to quickly measure time deltas.
      Some people also prefer time module ticks due to their lower
      memory footprint, esp. when it comes to storing thousands of
      time values in time series.

      > Victor's patch could easily be updated to return floats as well,
      > to make it compatible with the time module.
      >

      Victor reported implementing two methods, one to return a float and
      another to return a tuple. See msg124259. I am not sure I've seen
      that code.

      I had a look at the last patch on this ticket.

      > There's only one catch that Victor's patch doesn't include ...

      No, it is not about "only one catch". Victor's patch is simply wrong.
      For an aware datetime instance it extracts DST flag from tzinfo, but
      ignores the offset.

      True, so make that two issues ;-)

    20. malemburg commented on Apr 5, 2011

      @malemburg
      Member

      Alexander Belopolsky wrote:

      Alexander Belopolsky <belopolsky@users.sourceforge.net> added the comment:

      MAL> Since most of the datetime module was inspired by mxDateTime,
      MAL> I wonder why [ticks()/gmticks()] were left out. (msg75411)

      """
      The datetime module intended to be an island of relative sanity.
      Because the range of dates "timestamps" can represent varies across
      platforms (and even "the epoch" varies), datetime doesn't even try to
      produce timestamps directly -- datetime is more of an alternative to
      "seconds from the epoch" schemes. Because datetime objects have
      greater range and precision than timestamps, conversion is
      problem-free in only one direction. It's not a coincidence that
      that's the only direction datetime supplies ;-)
      """ - Tim Peters

      http://bytes.com/topic/python/answers/522572-datetime-timestamp

      I will also add that fromtimestamp() is not invertible in the presence of DST. That's why mxDatetime.ticks() takes a DST flag making it effectively a multi-valued function. Note that naive users, who just want to pass datetime values to an OS function expecting a float, most likely will not have means of properly obtaining DST flag.

      IMHO, the whole concept of DST is broken, but that's not our fault :-)

      Ditching the concept just because it is known to fail for
      one hour out of 8760 you have in a typical year doesn't really
      warrant breaking the "practicality beats purity" guideline.

      Otherwise, we'd have to ditch the date support in the datetime module
      too: after all, Feb 29 only exists every 4 years (well, most of the
      time) - and that's one day out of 1461 in those 4 years, so an
      even worse ratio :-)

      And I'm not even starting to talk about ditching the concept
      of Unix ticks to begin with, as a result of having leap seconds
      causing POSIX ticks values not matching (real) UTC ticks.

      In reality, all these things hardly ever matter and if they do,
      users will either know that they have to make conscious decision,
      simply don't care or decide not to care.

      BTW: A "timestamp" usually refers to the combination of date and
      time. The time.time() return value is "seconds since the Epoch".
      I usually call those values "ticks" (not sure whether it's standard
      term of not, but always writing "seconds since Epoch" wasn't an
      option either ;-)).

      Date/time is fun, isn't it ?

    21. abalkin commented on Apr 5, 2011

      @abalkin
      Member

      Let me state my position on this issue once again. Converting datetime values to float is easy. If your dt is a naive instance representing UTC time:

         timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

      If your dt is an aware instance:

         timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1)

      These recipes are easy to adjust for your application needs. One application may want millisecond or microsecond ticks, another might want to carry subsecond presision in a separate integer, third may want to avoid timestamps before 1970 or after 2038 or ignore microseconds altogether. No matter what a hypothetical datetime.epoch() will provide, most of applications will need to add a line or two to its code to serve their needs. Applications that will use dt.epoch() naively without thinking what dt represents (say local or UTC) will be buggy.

      The only related feature that I think is missing from datetime module is the ability to obtain local time as an aware datetime instance and to convert a naive datetime instance assumed to represent local time to an aware one.

      This is the subject of bpo-9527, but there is a resistance to adding that feature.

    22. abalkin commented on Apr 5, 2011

      @abalkin
      Member

      On Tue, Apr 5, 2011 at 1:45 PM, Marc-Andre Lemburg
      <report@bugs.python.org> wrote:
      ..

      BTW: A "timestamp" usually refers to the combination of date and
      time. The time.time() return value is "seconds since the Epoch".
      I usually call those values "ticks" (not sure whether it's standard
      term of not, but always writing "seconds since Epoch" wasn't an
      option either ;-)).

      In Unix context, the term "timestamp" is usually associated with the
      various time values that OS stores with the files. I think this use
      is due to the analogy with physical "received on" timestamps used on
      paper documents. Since it is well-known that Unix filesystems store
      time values as seconds since Epoch, it is common to refer to these
      values as "Unix timestamps".

      See, for example:

      http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html

    23. vivanov commented on Apr 7, 2011

      vivanovmannequin
      Mannequin

      On 04/05/2011 18:22, Alexander Belopolsky wrote:

      """
      The datetime module intended to be an island of relative sanity.
      ....... """ - Tim Peters

      Refusing to cooperate with the rest of the world is not sane by my books.

      On 04/05/2011 21:06, Alexander Belopolsky wrote:

      Converting datetime values to float is easy. If your dt is a naive instance representing UTC time:

      timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
      

      If your dt is an aware instance:

      timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1)
      

      Please add these lines to the datetime module's documentation. In some
      central, well lit place. I believe that if nothing else, the whole
      discussion should have proved to you that there are many people looking
      for them.

      OTOH a sinceepoch(epoch=datetime(1970,1,1)) method of the datetime class
      should be equally easy. Would be especially useful if few of the more
      frequently used EPOCHs are provided as constants.

    24. abalkin commented on Apr 7, 2011

      @abalkin
      Member

      On Thu, Apr 7, 2011 at 6:20 AM, Velko Ivanov <report@bugs.python.org> wrote:
      ..

      > Converting datetime values to float is easy.   If your dt is a naive instance representing UTC time:
      >
      >     timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
      >
      > If your dt is an aware instance:
      >
      >     timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1)

      Please add these lines to the datetime module's documentation. In some
      central, well lit place. I believe that if nothing else, the whole
      discussion should have proved to you that there are many people looking
      for them.

      This is precisely what I suggested at the end of msg132697 above. See
      attached patch (bpo-2736-doc.diff) for a proposed documentation
      enhancement.

    25. python-dev commented on Apr 25, 2011

      python-devmannequin
      Mannequin

      New changeset b55eac85e39c by Alexander Belopolsky in branch 'default':
      Issue bpo-2736: Documented how to compute seconds since epoch.
      http://hg.python.org/cpython/rev/b55eac85e39c

    26. added
      docsDocumentation in the Doc dir
      and removed
      stdlibStandard Library Python modules in the Lib/ directory
      on Apr 25, 2011
    27. python-dev commented on Jun 8, 2012

      python-devmannequin
      Mannequin

      New changeset 6671c5039e15 by Alexander Belopolsky in branch 'default':
      Issue bpo-2736: Added datetime.timestamp() method.
      http://hg.python.org/cpython/rev/6671c5039e15

    28. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    docsDocumentation in the Doc dirtype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions