Skip to content
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

Refactor time platform specific implementation #4502

Merged
merged 7 commits into from Jun 25, 2017

Conversation

bcardiff
Copy link
Member

@bcardiff bcardiff commented Jun 3, 2017

Time::Span ticks constants where moved to avoid circular dependency.

@bcardiff bcardiff added this to Issues in Windows Jun 3, 2017
@ysbaddaden
Copy link
Contributor

Maybe ticks don't have to be moved? Crystal::System::Time.compute_offset could return seconds (same as it's argument) instead of ticks, then have Time.compute_offset transform to ticks. This way, ticks would remain a Time implementation details, unrelated to the system calls that return seconds (and fractions of a second).

@RX14
Copy link
Contributor

RX14 commented Jun 3, 2017

My main concern is that taken on their own (as they should be), compute_offset and compute_second_and_tenth_microsecond are weird functions. They make perfect sense in the context of Time but when taken out they seem very arbitrary.

I agree with @ysbaddaden that compute_offset should return seconds, and probably be renamed to something more descriptive like compute_utc_offset or compute_local_offset. Additionally, I think compute_second_and_tenth_microsecond should be called compute_utc and just return ticks. The unix epoch is a platform specific thing (windows uses 1 Jan 1601 as an epoch) so i'd rather the method do more.

@ysbaddaden
Copy link
Contributor

I prefer an explicit{seconds, fraction) tuple over ticks. I agree the epoch should be applied since it's system related, so seconds means seconds from 0 instead is seconds since X. Unless we introduce a system specific EPOCH constant maybe? Thought I'm not sure it would useful.

@RX14
Copy link
Contributor

RX14 commented Jun 3, 2017

@ysbaddaden the tuple is so that we don't need to do conversions back and forth from ticks, correct?

@@ -0,0 +1,22 @@
# :nodoc:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to :nodoc: Crystal as we loose documenting macros and Crystal::VERSION. The :nodoc: should be placed on Crystal::System only.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. I did that on the random PR!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed (in master as well)

end

def self.compute_second_and_tenth_microsecond
{% if flag?(:darwin) %}
Copy link
Contributor

@RX14 RX14 Jun 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be separated out into a file just for darwin? How about requiring this (unix) file and a darwin file which overrides compute_second_and_tenth_microsecond or would that be too messy?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens once and it's 3 lines. It seems more complicated to extract it... so I guess it's acceptable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move it to a separate file. I think inside a given System implementation there shouldn't be any if flag?, otherwise it kind of missing the point of extracting it into a different place.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splitting darwin and unix makes this harder to understand I think. One function is shared. The other don't. I tried splitting them but I was not happy with the result. Now the responsibilities of the System::Time is more clear and the windows implementation will be in a different file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe macOS Sierra added support for clock_gettime, so maybe the condition will go away, someday.

@bcardiff
Copy link
Member Author

bcardiff commented Jun 5, 2017

Functions renamed. Now the {seconds, fraction} is from absolute 0. Which kind of match the ::Time representation a bit more.

The only platform specific in ::Time are now a constructor that references LibC::Timespec which is used in File::Stat.

@bcardiff bcardiff changed the title Refator time platform specific implementation Refactor time platform specific implementation Jun 17, 2017
@bcardiff
Copy link
Member Author

Since the seconds in Crystal::System::Time.compute_utc_offset is now absolute from 0 and always an Int64, in the 32bits platform there was an issue in when calling LibC.localtime_r(pointerof(seconds), out tm) . That make me notice an issue that UnixEpochInSeconds was not been subtracted from the argument. Now that is done and a seconds_from_epoch = LibC::TimeT.new(seconds - UnixEpochInSeconds) ensures the right time is used for LibC.localtime_r(pointerof(seconds_from_epoch), out tm)

@bcardiff
Copy link
Member Author

@RX14 , @ysbaddaden I would appreciate another pair of eyes before merging this. I fix an issue discovered by 32 bits, hopefully the only thing left is #4502 (comment) .

@ysbaddaden
Copy link
Contributor

I think the API will eventually change, but for the time being this is fine. Maybe replace if flag?(:darwin) to something more generic, that would play well if C bindings are automatically generated, someday (and would pick clock_gettime on macOS >= Sierra but gettimeofday for older releases):

if LibC.methods.includes?("clock_gettime".id)
  # clock_gettime
else
  # fallback to gettimeofday
end

BTW: what may change is that we need a broken down time representation to determine the offset, using tm + mktime on POSIX, or SYSTEMTIME + DYNAMIC_TIME_ZONE_INFORMATION on Windows, or later from IANA tables directly. For example In my add-offset-to-time refactor, I currently have this:
https://gist.github.com/ysbaddaden/75ad2b4a4f75be92757b4d253cfa885b

# :nodoc:
module Time
# Returns the number of seconds that you must add to UTC to get local time.
# *seconds* are absolutes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by *seconds* are absolutes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It means seconds elapsed from 0, not from unix epoch as it was before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say "from 0" it's not at all clear you're referring to the Gregorian epoch. I'd say something like *seconds* are measured from the Gregorian epoch (01 January 0001 00:00:00)

# *seconds* are absolutes.
# def self.compute_utc_offset(seconds)

# Returns the current utc time meassured in absolute `{seconds, tenth_microsecond}`
Copy link
Contributor

@RX14 RX14 Jun 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@bcardiff bcardiff merged commit e92d280 into crystal-lang:master Jun 25, 2017
@bcardiff bcardiff added this to the Next milestone Jun 25, 2017
@straight-shoota straight-shoota moved this from Done to Stdlib in Windows Jan 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Windows
  
Stdlib
Development

Successfully merging this pull request may close these issues.

None yet

4 participants