From: Timur Safin via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: "'Igor Munkin'" <imun@tarantool.org> Cc: tarantool-patches@dev.tarantool.org, v.shpilevoy@tarantool.org, Alexander Turenko <alexander.turenko@tarantool.org> Subject: Re: [Tarantool-patches] [RFC PATCH 00/13] Initial datetime support Date: Thu, 22 Jul 2021 15:54:39 +0300 [thread overview] Message-ID: <281601d77ef8$bc0b3800$3421a800$@tarantool.org> (raw) In-Reply-To: <20210722100133.GL11494@tarantool.org> Hello Igor, Please see some responses (but better see the next iteration of patchset to be sent later) : From: Igor Munkin <imun@tarantool.org> : Subject: Re: [RFC PATCH 00/13] Initial datetime support : : Timur, : : Thanks for the series! I wonder, why you decided to reinvent several : approaches being already used for quite similar Tarantool types: decimal : and uuid. Frankly speaking, I expect you introduce datetime the very : *very* similar way. I didn't make the precise review for this series : (this is waste of time), so please consider my major comments below. : : Let's start with top 3 comments to the eye catching problems I've found : while looking at the patches. : : 1. Tests have to be committed in the same scope the corresponding : changes in Tarantool are introduced. : 2. Docbot request is required for the changes you're introducing: this : is the place where you can leave the description you've added below. : 3. Please consider approaches used for decimal and uuid: almost every : Oleg's comment came from the bugs fixed for these types. : : As I write above, this is not a precise review, so I don't even start : nitpicking the patches and simply address you to this document[1] and : our dev guide[2]. Please, check whether your next series respects these : guidelines. : : On 15.07.21, Timur Safin wrote: : > Here is the preliminary RFC version of a patchset, which is implementing : > datetime lua support in box, their messagepack, yaml, json serialization : > support, and a set of c and lua tests. : > : > * It's heavily influenced by Sci-Lua lua-time module implementation : > https://github.com/stepelu/lua-time : > e.g. you could find very similar approach for handling of operations : > with year and months periods (which should be handled differently than : > usual seconds, days periods). : > : > * But internally it actually uses Christina Hanson' c-dt module : > https://github.com/chansen/c-dt : > (though it has been modified slightly for cleaner integration : > into cmake build process) : : BTW, submodule points to the very strange repo: please use either : vanilla one, or create a fork into Tarantool repositories. At the moment it points to my own fork, because I do not have Permissions, and unable to create new repo in our organization. I'll ask Sasha Turenko for a help in moving this repo. : : > : > This is preliminary version of patchset, with unoptimal patches divisions : > (like you could see patches with rename refactorings), but, due to an : amount : > of code in patchset, and limited time have, I send patchset as RFC today, : > expecting to receive initial feedback for various parts of a series. : : Well, I guess I can stop here for the initial feedback. : : I have no idea, why you decided to introduce a separate tiny module : src/lua/datetime.c just for initializing several constants and a : oneliner for pushing datetime GCcdata on Lua stack. This module is : excess. Please consider the way this is done for uuid and move : everything to src/lua/utils.c that encloses all illegitimate tricks with : Lua C API. I'll look there. : : > : > Prior plan was to split series into one, which introduces datetime module : api, : > and another one with datetime messagepack serialization implementation. : > But here they left as part of a same series. Sorry, for invonvenience - : I'll : > reshuffle order according to feedback provided. : : [I personally don't know what kind of the feedback you need to reshuffle : the series...] : : > : > The problem, which was stopping such simple division - that `datetime.lua` : > module uses `datetime_to_string()` ffi function for stringization of a : > datetime object. And this function has been introduced as part of : > messagepack/yaml/json serialization support. Yes, intra-dependendencies : > between parts looks suboptimal, and I'm very open to suggestions how to : > divide it properly. : : Again, vse uje ukradeno^W pridumano do nas: consider the way this is : solved for uuid (within src/lib/uuid/tt_uuid.[ch]), since you've chosen : FFI approach for this type (we'll return to this question later). I've seen tt_uuid library, will consider extraction of datetime stringization Helper somewhere similarly to tt_uuid. : : > : > Module API : > ========== : > : > To simplify review of a code in patchset below you could find preliminary : > documentation of a datetime api module. Eventually we may put it : > as .rst file in documentation repository (though, personally, I'd prefer : > to have all modules api committed to the same repo as code, but I digress) : : I guess, I'll leave general comments right here. : : 1. <asctime>, <strftime>, <ctime> can be implemented via FFI by user, : and you simply provide a wrapped. Anyway, it's already implemented, : so OK. : 2. IMHO, you test too many exotic formats and corner cases of creating : datetime object. I doubt somebody will use at least 10% of the : provided functionality (especially in beta). Those are types of standard ISO-8601 date/time formats with few extensions. : 3. Datetime and interval arithmetics -- this is what bother me a lot. : I believe every average Lua user can parse date into the table and : build the string from this table back. But nobody wants to mess with : all that hell with leap years arithmetics, leap seconds, etc. Agreed that convenient interval arithmetic is the most important part of datetime module. : 4. Furthermore, I don't understand the following behaviour: : | tarantool> d = require('datetime') : | --- : | ... : | : | tarantool> ft = require('ffi').typeof : | --- : | - +2 days, 0 hours, 0 minutes, 0 seconds : | ... : | : | tarantool> d.days(2) + d.days(1) : | --- : | - 1970-01-04T00:00Z : | ... : | : | tarantool> ft(d.days(2) + d.days(1)) : | --- : | - ctype<struct datetime_t> : | ... : | : | tarantool> d.days(2) - d.days(1) : | --- : | - error: 'builtin/datetime.lua:554: date/time expected' : | ... : | : I believe it's quite natural to do arithmetics with intervals to : create a new one, isn't it? At the moment there was limitation that at least 1 of 2 arguments passed (either left or right) have to be full datetime object, and only another one could be interval. (Though in __add we could summarize 2 intervals, as you've shown above, but that was oversight in original patchset, which later has been "fixed") Now, while you are mentioning it, I tend to agree that it's ok to summarize or subtract 2 intervals, and I'll relax this restriction. : : > : > Datetime module : > =============== : > : > This module allows to parse date/time stamps, manipulate with them, and : > generate textual representation. Parsing of date constants will handle : > all ISO-8601 formats, and deal with some extensions. : > : > For internal date representation it uses cdata structures of a form: : : BTW, I agree w/ Oleg and see no motivation why FFI is chosen for : implementation: decimal is implemented via Lua C API, uuid -- via FFI. : Are there any proofs and benchmarks for datetime? Does it violate any : limit mentioned here[1]? Using ffi to call c-dt was an obvious, easiest way to call c-dt. And taking into account that uuid is still using FFI I conclude there is no strict policy here and ffi is acceptable. Did not understand "Does it violate any limit mentioned here[1]?" what are you talking about here? Could you please elaborate? : : > : > ```c++ : > struct t_datetime { : > int secs; : > int nsecs; : > int offset; : > }; : > ``` : > : > Where: : > : > - secs is the (signed) number of seconds since epoch 1970-01-01T00:00Z; : > - nsecs is number of nanoseconds since beginning of day; : > - offset is the timezone offset (in minutes); : > : > `datetime()` ? create datetime object : > ------------------------------------- : > : : Both decimal and uuid modules provides <new> function, but you decided : to name the datetime constructor <datetime>. I see no reason for such : inconsistency. Will add `new` as entry point. But, WFIW, here we use the same approach as in uuid.lua where uuid() is shortcut for uuid.new() : : > Create date/time object using either string literals, or initialization : > object. When given string literals it behaves like wrapper around : > parse() method. : > : > When there is initialization object it could create date/time object : > using these attributes below: : > : > | **Easy way** | : | : > |--------------|---------------------------------------------------------- : ---------------------------------------| : > | secs | Seconds since epoch : | : > | nsec | Nanoseconds since midnight : | : > | offset | Time-zone offset in minutes : | : > | **YMD part** | : | : > | year | Year in range \[1..9999\] : | : > | month | Month in range \[1..12\] : | : > | day | Day in month in range \[1..31\] : | : > | **HMS part** | : | : > | hour | Hour in range \[0..23\] : | : > | minute | Minute in range \[0..59\] : | : > | second | Seconds in range \[0..60\]. It allows to have fraction : part in which case it goes to nsec field | : > | tz | Timezone offset (in minutes) for HMS part : | : > : > Example: : > : > ```lua : > : > datetime = require `datetime` : > : > d = datetime{secs = 0, nsec = 0, offset = 0} : > d = datetime(?1970-01-01?) : > d = datetime{year = 1970, month = 1, day = 1} : > ``` : > : > `delta()` ? create time duration object : > --------------------------------------- : > : > TBD : : Why delta? Sci-Lua uses period, that is quite accurate term. SQL : provides INTERVAL type. I guess you can choose something from this. Yup, interval is much better name, will use it instead. : : > : > `parse()` ? parse full ISO-8601 string : > -------------------------------------- : > : > Parse full length date/time literal, which may be in ISO-8601 format of : > any of extended formats supported by `parse_date()`, `parse_time()` or : > `parse_timezone()` : > : > It deals with date/time string in format : > : > `date ([Tt ] time ([ ] time_zone)? )?` : > : > Where time or `time_zone` parts may be omitted. : > : > Example: : > : > ```lua : > : > datetime = require `datetime` : > : > d = datetime.parse(`1970-01-01`) : > d = datetime.parse(`1970-01-01T00:00:00Z`) : > d = datetime.parse(`1970-01-01T02:00:00+02:00`) : > ``` : > : > `parse_date()` ? parse ISO-8601 date literal : > -------------------------------------------- : > : > Parse date string literal, return partial date object which has : > precision of up-to date period of time. : > : > A number of standard ISO-8601 formats supported, plus there are some : > relaxed formats which are of frequently use: : > : > | Basic | Extended | | : > |----------|------------|--------------------------| : > | 20121224 | 2012-12-24 | Calendar date (ISO 8601) | : > | 2012359 | 2012-359 | Ordinal date (ISO 8601) | : > | 2012W521 | 2012-W52-1 | Week date (ISO 8601) | : > | 2012Q485 | 2012-Q4-85 | Quarter date | : > : > `parse_time()` ? parse ISO-8601 time literal : > -------------------------------------------- : > : > Parse time string literal, return partial date/time object, which : > defines time period inside of single date. : > : > A number of standard ISO-8601 formats supported, plus there are some : > relaxed formats which are of frequently use: : > : > | Basic | Extended | : > |-------------------|---------------------| : > | T12 | N/A | : > | T1230 | T12:30 | : > | T123045 | T12:30:45 | : > | T123045.123456789 | T12:30:45.123456789 | : > | T123045,123456789 | T12:30:45,123456789 | : > : > The time designator T may be omitted. : > : > `parse_zone()` ? parse ISO-8601 time zone : > ----------------------------------------- : > : > Parse time-zone string literal, return partial date/time object, which : > defines timezone offset in minutes sing GMT. : > : > A number of standard ISO-8601 formats supported, plus there are some : > relaxed formats which are of frequently use: : > : > | Basic | Extended | : > |-------|----------| : > | Z | N/A | : > | ?hh | N/A | : > | ?hhmm | ?hh:mm | : : AFAIU, <parse_{date,time,zone}> are the parts of <parse> routine, right? : Then why do you provide a separate interfaces for these purposes? Because there are some cases when you need to parse parts of full date-time literal, like parsing only time part. I kept them public, similarly to how it was done in the original c-dt. I see not much point to hide them if we already have such building blocks for external consumption. : : > : > `tostring()` ? convert datetime object to string : > ------------------------------------------------ : > : > Return string representation (probably compact if there are some parts : > missing) of a date-time objects passed : > : > `now()` ? return current date/time : > ---------------------------------- : > : > `now()` returns local date and time object. It will use local time-zone : > and nanosecond precision. : > : > `strftime()` ? convert date object to string using format : > --------------------------------------------------------- : > : > `strftime()` is the FFI wrapper around strftime() function in LIBC. It : > supports all the same flags which supports strftime() from host OS. : > : > See : > <https://pubs.opengroup.org/onlinepubs/000095399/functions/strftime.html> : > for more details. : > : > `asctime()` ? convert date object to string using asctime predefined : format : > -------------------------------------------------------------------------- : - : > : > `asctime()` is the FFI wrapper over `asctime_r()` from a host libc. : asctime : > returns string in the form `"Sun Sep 16 01:03:52 1973\\n\\0"` : > : > <https://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html> : > : > `ctime()` ? convert local time to string using ctime() predefined format : > ------------------------------------------------------------------------ : > : > `ctime()` is the FFI wrapper over `ctime_r()` in the host libc. ctime : > returns string in the form `"Sun Sep 16 01:03:52 1973\\n\\0"` : : This is not quite right, considering your code, so here is the question: : do you mean ctime(3) or ctime_r(3). ctime_r is _reentrant_ version of ctime, which behave identically. I'll use more careful wording then, to not confuse reader with 2 separate names. : : > : > <https://pubs.opengroup.org/onlinepubs/009695399/functions/ctime.html> : > : > The difference of `ctime()` and `asctime()` is that former is returning : > local time zone formatted, while the latter will deal with GMT. : > : > Examples: : > : > ``` : > tarantool> date = require 'datetime' : > --- : > ... : > tarantool> T = date.now() : > --- : > ... : > tarantool> T : > --- : > - 2021-07-14T01:36:48.554105+03:00 : > ... : > tarantool> date.asctime(T) : > --- : > - 'Tue Jul 13 22:36:48 2021 : > ' : > ... : > tarantool> date.ctime(T) : > --- : > - 'Wed Jul 14 01:36:48 2021 : > ' : > ... : > ``` : > : > Date attribute accessors : > ------------------------ : > : > | | : | : > |----------------|-------------------------------------------------------- : ---------| : > | `timestamp` | Calculate timestamp with seconds and nanoseconds parts : combined | : > | `nanoseconds` | Number of nanoseconds in time part : | : > | `microseconds` | Number of microseconds in time part : | : > | `milliseconds` | Number of milliseconds in time part : | : > | `seconds` | Alias to timestamp : | : > | `minutes` | Number of minutes in time part : | : > | `hours` | Number of hours in time part : | : > | `days` | Number of days in time part : | : > : > ``` : > tarantool> d = date{year = 1970, month = 1, day = 1, hour = 0, minute = : 10, second=10} : > tarantool> d.secs : > --- : > - 610 : > ... : > tarantool> d.nsec : > --- : > - 0 : > ... : > tarantool> d.offset : > --- : > - 0 : > ... : > tarantool> d.nanoseconds : > --- : > - 610000000000 : > ... : > tarantool> d.milliseconds : > --- : > - 610000 : > ... : > tarantool> d.hours : > --- : > - 0.16944444444444 : > ... : > tarantool> d.minutes : > --- : > - 10.166666666667 : > ... : > ``` : > : > Date arithmetic : > --------------- : > : : The most interesting part of the doc by the way. Yeah, agreed. See it soon! : : > TBD : > : > : > https://github.com/tarantool/tarantool/issues/5941 : > https://github.com/tarantool/tarantool/issues/5946 : > https://github.com/tarantool/tarantool/tree/tsafin/gh-5941-datetime-V2 : > : > : > ... : : [1]: https://github.com/tarantool/tarantool/wiki/Code-review-procedure : [2]: https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/ : [1]: http://luajit.org/ext_ffi_semantics.html#status : : -- : Best regards, : IM Regards, Timur
prev parent reply other threads:[~2021-07-22 12:54 UTC|newest] Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-07-15 8:18 Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 01/13] build: add Christian Hansen c-dt to the build Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 02/13] lua: built-in module datetime Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 03/13] test: datetime test Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 04/13] test: datetime string formatting Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 05/13] box: add messagepack support for datetime Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 06/13] lua: positive/negative cases in datetime test Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 07/13] lua: asctime and strfime fixed Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 08/13] box, lua: renamed t_datetime_tz structure to datetime_t Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 09/13] lua: calculated attributes for date Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 10/13] lua: tostring formatization in datetime.lua Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 11/13] test: allow relaxed date format without tz Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 12/13] lua: initial time duration support Timur Safin via Tarantool-patches 2021-07-15 8:18 ` [Tarantool-patches] [RFC PATCH 13/13] lua: complete " Timur Safin via Tarantool-patches 2021-07-15 16:56 ` [Tarantool-patches] [RFC PATCH 00/13] Initial datetime support Oleg Babin via Tarantool-patches 2021-07-15 23:03 ` Timur Safin via Tarantool-patches 2021-07-16 6:58 ` Oleg Babin via Tarantool-patches 2021-07-22 10:01 ` Igor Munkin via Tarantool-patches 2021-07-22 12:54 ` Timur Safin via Tarantool-patches [this message]
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to='281601d77ef8$bc0b3800$3421a800$@tarantool.org' \ --to=tarantool-patches@dev.tarantool.org \ --cc=alexander.turenko@tarantool.org \ --cc=imun@tarantool.org \ --cc=tsafin@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [RFC PATCH 00/13] Initial datetime support' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox