Open MannarAmuthan opened 11 months ago
Looks like there is some issue in handling gmt in windows, will fix it
Appreciate the work you've done on this so i've stuck the hacktoberfest label on it (if you're participating) until I get some time to thoroughly check it and get it merged in!
I think I'm going to work on this PR (unless you want to continue with it) so that all of the object methods return a Datetime object rather than primitive values and have extra methods on the datetime object to convert to string / numeric values (toString like you have, or toEpoch).
Means as we add more methods we can much easier chain things (e.g like addHour or whatever)
Certainly, could you provide some contract ideas that I can attempt to implement ?. Because current methods such as datetimeObj.strptime, datetimeObj.strftime could not return Datetime object. Am I right?
Exactly yeah, we'd leave the current ones in and they can return the primitive values. Your new object methods would instead return a Datetime object, so:
Datetime.new(<values>); -> Datetime
Datetime.strptime(<string>, <string>); -> Datetime
Datetime.getTime(); -> Number
Datetime.strftime(<string>); -> String
Datetime.toString(); -> String (thinking do we need this if we have strftime actually? we could have this be strftime with no format specifier passed to it)
// Later down the line
Datetime.addMinutes(<number>); -> Datetime
Datetime.addHours(<number>); -> Datetime
...
Thanks for Suggestions, I assume that we have two different types of methods/functions, one is on Datetime module, and another is on Datetime object itself.
Datetime.new(); -> Datetime(Object) , current time object Datetime.newUTC(); -> Datetime(Object) , current time object
Datetime.new(
dateTime(object).strftime(
dateTime(object).addMinutes(
Apologies yeah, strptime to return a date time object rather than a number, and then getTime to return a number
I had \
No rush or anything @MannarAmuthan but just checking if you're still working on this?
Hi yes , I am planning to work on this in weekend
Hi @Jason2605 , Please look into it, and provide any suggestions or changes needed.
Will take a look later today, thanks @MannarAmuthan
@briandowns Be good to get your thoughts on this too
I like this.
I'm curious if we could simplify it though.
I was looking at working on a time module myself at one point and was going to model it after the Time package in Go. Essentially, the Time type is just a number and operations are performed on that value(s). There's a Duration type as well which is just an alias for an int64. The package's API is small and clean as well. https://cs.opensource.google/go/go/+/master:src/time/time.go;drc=bc2124dab14fa292e18df2937037d782f7868635;l=135
Hi @briandowns , That one is great reference, Thanks for this !
I assume we are talking about the structure of datetime object , will take look into it.
I like this.
I'm curious if we could simplify it though.
I was looking at working on a time module myself at one point and was going to model it after the Time package in Go. Essentially, the Time type is just a number and operations are performed on that value(s). There's a Duration type as well which is just an alias for an int64. The package's API is small and clean as well. https://cs.opensource.google/go/go/+/master:src/time/time.go;drc=bc2124dab14fa292e18df2937037d782f7868635;l=135
Yeah this is an interesting concept, will need to have a deeper look through the Go source but I think representing the time as a number internally makes a lot of sense to me
Actually I read more on this, and found that the classic _timet epoch integer, represents time after 1970. I changed the code, it is working fine,
New structure:
typedef struct { long time; / timestamp integer/ int is_local; } Datetime;
But I worry, that we need the capability to represent/create Datetime before 1970 also. If you have any thoughts on this let me know.
As always, I'll defer to @Jason2605 but I think we can be fine with storing a wall time and mono time in int64_t values in a dateTime object. From there, that single object can be used for timers, time diffs, and we can cast up and down from time_t. In the case of timestamps prior to epoch, they end up being negative numbers.
As always, I'll defer to @Jason2605 but I think we can be fine with storing a wall time and mono time in int64_t values in a dateTime object. From there, that single object can be used for timers, time diffs, and we can cast up and down from time_t. In the case of timestamps prior to epoch, they end up being negative numbers.
Honestly for this one, I'd probably go with whatever the go library is doing (still need to properly look at it sorry). A single numeric value storing the current time sounds perfect to me and going into negative numbers for dates prior to 1970 is fine (and what happens when you want a time before then when using unix time anyways yeah)
A simple and naive assumption of how this might look:
typedef int64_t Duration;
Duration microseconds(const Duration d) {
return (Duration)d * 1e3;
}
Duration milliseconds(const Duration d) {
return (Duration)d * 1e6;
}
Duration parseDuration(const char *s) {
// convert strings like "1s" to a duration of 1 second
Duration d;
return d;
}
typedef struct {
int64_t wall;
int64_t mono;
} DateTime;
DateTime now() {
struct timespec wall, mono;
clock_gettime(CLOCK_MONOTONIC, &mono);
clock_gettime(CLOCK_REALTIME, &wall);
DateTime dt;
dt.mono = mono.tv_sec;
dt.wall = wall.tv_sec;
return dt;
}
DateTime add(const DateTime dt, Duration d) {
DateTime ndt;
ndt.wall += dt.wall;
return ndt;
}
DateTime sub(const DateTime dt, Duration d) {
DateTime ndt;
ndt.wall -= dt.wall;
return ndt;
}
Duration since(const DateTime dt, const Duration d) {
DateTime ndt = sub(now(), d);
return (Duration)ndt.wall;
}
Rooted off of the DateTime class, we can any number of methods that will use the values therein. Timers using mono, time and date operations using wall.
Thanks for all suggestions, I am planning to work on this , will provide updates
Currently, I have created a datetime object to store time as an integer and included a flag for location (local or not). However, this is not quite complete; I need to implement ADD and SUB methods ( and duration ) to ensure proper functionality. I will investigate this further and continue working on it.
Thanks for still working on this! Will be a really nice addition to get a more fully featured datetime library
Naming: The name timedelta is inspired from python datetime package , meanwhile duration also makes sense
Note: These are just initial thoughts, welcom more suggestions, even hybrid approaches.
To Remember: In Dictu, there is no named or keyword arguments for function calls, which restrict us to defining clear contract for timedelta object.
mydatetime = Datetime.new();
toAdd = Timedelta({
'days': 2,
'hours': 1
}); // Can have year , month, etc
mydatetime.add(toAdd); // Returns new datetime object
mydatetime = Datetime.new();
mydatetime.addDays(1);
mydatetime.addMinutes(2);
mydatetime.addYears(1);
//etc
or
mydatetime = Datetime.new().addDays(1).addMinutes(2).subSeconds(1);
Thanks very much for the detailed write up! I personally think the Timedelta option is the way to go - I feel like when dealing with calculating time differences it will be a lot easier to conditionally create a timedelta object than it will be to apply different methods - it also means we will be able to have an actual value representation of a length of time (we can then apply nice string methods to this for example)!
No kwargs is a valid gripe and would be a really nice addition, but as you say for now, a dictionary would be the next best replacement for instantiation
Be good to hear your thoughts too @briandowns
I like the idea of a timedelta object. I have one tiny thought though. I'm more of a fan of having time objects be immutable since they represent a single point on a linear track. If we need to adjust the object by adding or subtracting time, I'd like a new object. We then have the ability to do compare operations.
Yeah when you run .add
or .minus
(or whatever we decide the public API to be) I would expect a new datetime object yeah!
I'm not too fussed on Duration vs Timedelta either, Luxon a popular JS library seems to use Duration whereas Python's implementation as mentioned uses Timedelta, so open to either on the naming front.
Comparisons of objects will be an interesting one in the sense of would you expect the standard operators to work with these types (< > != ==) or would we have comparison methods (potentially opens up the question of user defined operator overloading too but can save that for another day)
I'm not too concerned around naming Go uses an int64 as type Duration. Meh.
As for object comparison, I'd probably at least expect a couple methods like t2.equals(t1);, and maybe a diff method.
So you'd prefer methods rather than overloading the operators?
Makes sense, yeah I think im siding towards Duration
at the moment
Yeah, for sure for methods over operators. Seems like the surface area for that is super small and still achieves the necessary functionality.
If this has stagnated, I'd like to pick it up.
If this has stagnated, I'd like to pick it up.
Have at it mate!
Implemented Datetime object
Resolves: #647
What's Changed:
I didn't removed old contracts yet, means there is no any breaking changes, confirmed with tests. Added instantiation for datetime objects, once we agreed on these contracts, other utility methods for this datetime objects can be implemented on top of it.
Type of Change:
#
Housekeeping:
#
Added methods for datetime object
Constructors
Methods