The Problem with Time & Timezones - Computerphile

By: Computerphile

39499   374   1383639

Uploaded on 12/30/2013

A web app that works out how many seconds ago something happened. How hard can coding that be? Tom Scott explains how time twists and turns like a twisty-turny thing. It's not to be trifled with!

A Universe of Triangles: http://www.youtube.com/watch?v=KdyvizaygyY
LZ Compression in Text: http://www.youtube.com/watch?v=goOa3DGezUA
Characters, Symbols and the Unicode Miracle: http://www.youtube.com/watch?v=MijmeoH9LT4

More from Tom Scott: http://www.youtube.com/user/enyay and https://twitter.com/tomscott

http://www.facebook.com/computerphile
https://twitter.com/computer_phile

This video was filmed and edited by Sean Riley.

Computerphile is a sister project to Brady Haran's Numberphile. See the full list of Brady's video projects at: http://bit.ly/bradychannels

Comments (18):

By anonymous    2017-09-20

strtotime() is an amazingly useful function for something like this. It accepts a wide variety of natural language and date/time inputs.

20 weeks from exactly now

echo date('c',strtotime('+20 weeks'))."\n";

20 weeks from the start of that day

echo date('c',strtotime('08/03/2017 +20 weeks'))."\n";

Your answer in php:

$disabled_dates = "08/10/2017, 08/17/2017";
$start_date = "08/03/2017";
$num_of_weeks = "20";

$the_end = strtotime($start_date.' GMT +'.$num_of_weeks.' weeks');

//make all the disabled dates into timestamps for easy comparison later
$disabled_dates_array = array();
foreach(explode(',', $disabled_dates) as $date){
  $disabled_dates_array[] = strtotime(trim($date).' GMT');
}

//now compare and delay the end date if needed
foreach($disabled_dates_array as $timestamp){
  //if there was a disabled date before the end, add a day's worth of seconds
  //strtotime() returns false if it can't parse the date, so make sure it's truthy
  if($timestamp && $timestamp <= $the_end){
    $the_end += 86400;
  }
}

$enddate = date('m/d/Y',$the_end);

Edit 1: added GMT to all strtotime() conversions, to avoid issues with daylight saving times changing the amount of seconds between dates. Some days are 23 hours and some are 25 because of daylight saving time. Leap seconds are not an issue in unix time.

Edit 2: Answer in javascript:

var disabled_dates = "08/10/2017, 08/17/2017";
var start_date = "08/03/2017";
var num_of_weeks = "20";

var the_end = Date.parse(start_date + ' GMT') + parseInt(num_of_weeks)*7*86400*1000;

//in javascript Date.parse is similar to php's strtotime,
//but it returns milliseconds instead of seconds
disabled_dates = disabled_dates.split(", ");
for(var i = 0, len = disabled_dates.length; i < len; i++){
  disabled_dates[i] = Date.parse(disabled_dates[i] + ' GMT');
  if(disabled_dates[i] && disabled_dates[i] <= the_end){
the_end += 86400000;
  }
}

the_end = new Date(the_end);
var enddate = ('0' + (the_end.getUTCMonth() + 1)).substr(-2) + '/' + ('0' + the_end.getUTCDate()).substr(-2) + '/' + the_end.getUTCFullYear();
console.log(enddate);

Here I ran into a problem with daylight saving time as

Sun Oct 29 2017 00:00:00 GMT+0100 (GMT Daylight Time) + 24 hours =
Sun Oct 29 2017 23:00:00 GMT+0000 (GMT Standard Time)

So adding ' GMT' (GMT Standard Time) at the end of the dates is important, otherwise the results may be off by a day.

This video gives some insight into how keeping time can become complicated.

Original Thread

By anonymous    2017-09-20

Well, this is not so trivial because Idris requires proofs from you on every step especially if you're using dependent types. All basic ideas are already written in this question:

Is there a way to define a consistent date in a dependent type language?

I'll comment your implementation and translate code in answer (it's probably Agda) to Idris. Also I made few adjustments to make your code total.

First, Month can be written a little bit simpler:

data Month = January
           | February
           | March

I'm not going to write all 12 month, it's just an example.

Second, Year type should store Nat instead of Integer because most functions that work with Integer aren't total. This is better:

data Year : Type where
    Y : Nat -> Year

It helps to make isLeapYear check total:

isLeapYear : Year -> Bool
isLeapYear (Y y) = check4 && check100 || check400
  where
    check4 : Bool
    check4 = modNatNZ y 4 SIsNotZ == 0

    check100 : Bool
    check100 = modNatNZ y 100 SIsNotZ /= 0

    check400 : Bool
    check400 = modNatNZ y 400 SIsNotZ == 0

Next, it's not good to make Day as a Fin 32. Better to specify day's number for each month specifically.

daysInMonth : Month -> Year -> Nat
daysInMonth January  _    = 31
daysInMonth February year = if isLeapYear year then 29 else 28
daysInMonth March    _    = 31

Day : Month -> Year -> Type
Day m y = Fin (daysInMonth m y)

And you should adjust a little your Date record:

record Date where
    constructor MkDate
    year  : Year
    month : Month
    day   : Day month year

Well, now about addDays. This function is actually very complex when you're working with dependent types. As you correctly noticed, you have several cases. For example: sum fits in the current month, sum goes to next month, sum skips several months, sum goes to year. And each such case need proof. If you want to ensure that sum fits in current month, you should provide a proof of that fact.

Before I move to code I want to warn you that writing even non-typed versions of date library is increadibly hard. Moreover, I suppose nobody haven't still tried to implement full-featured version in some language with dependent types. So my solution may be far from the best. But at least should give you some ideas about what you're doing wrong.

Then you can start with writing some function like this:

daysMax : (d: Date) -> Nat
daysMax (MkDate y m _) = daysInMonth m y

addDaysSameMonth : (d : Date)
                -> (n : Nat)
                -> Prelude.Nat.LT (finToNat (day d) + n) (daysMax d)
                -> Date
addDaysSameMonth d n x = ?addDaysSameMonth_rhs

Well, numeric operations with Fin are very limited according to current state of Data.Fin module. So you may have hard times even adding two Nats and converting them to Fin using given proof. Again, writing such stuff is harder than it seems :)

Here is the full sketch of code: http://lpaste.net/3314444314070745088

Original Thread

By mikehollinger    2017-09-20

I'll just leave this here:

Have a look at a j excellent video that explains why time algorithms are hard to sort out: https://m.youtube.com/watch?v=-5wpm-gesOY

Happy New Year from Austin!

Original Thread

By Pxtl    2017-09-20

Computerphile has a wonderful video about dates that covers this subject perfectly. Mandatory viewing on my team before anybody has a problem involving dates.

https://m.youtube.com/watch?v=-5wpm-gesOY

Original Thread

By anonymous    2017-09-23

Before I answer your question, I would like to mention that time and date handling is a lot deeper than it may first appear, and that generally it's bad practice to reinvent the wheel. Consider using the excellent moment.js to parse, process and display your dates.

With that out of the way, let's zero-pad those dates.

You're using parseInt which parses a string into an integer. However, 01, 02, 03 etc are not valid integers - you will need to output strings.

One way to do this is:

function zeroPad(number)
{
    return ('0' + String(number)).slice(-2);
}

Which you can then call like:

console.log(inst.selectedYear+'-'+zeroPad(parseInt(inst.selectedMonth)+1)+'-'+zeroPad(i));

Note that the String() call isn't necessary (JavaScript will implicitly typecast number to a string), but I prefer to be explicit with these things.

Original Thread

By anonymous    2017-10-01

HANG ON... First things first, I love anything to do with time and I love that link (bookmarked). It reminds me of a Tom Scott video ( https://www.youtube.com/watch?v=-5wpm-gesOY ), where he talks about some app he made at one point dealing with time, timezones, daylight savings, varying calendars and leap seconds. Everything in it I knew except for the "leap second smear"!! Good one google!

Original Thread

By anonymous    2017-10-22

Any reason why storing the offset of user's timezone is NOT a good idea?

Yes. Many. A time zone and an offset are not the same thing. A time zone represents a geographical area in which local time is aligned. A time zone may undergo several different changes in its offset from UTC. Some of which are regular (like daylight saving time), and some of which are irregular (like when a government changes its standard time or dst rules).

... In my case, I simply want to display all date time values in user’s current time zone so that they’re meaningful to the user.

Ok, so let's say you check the user's current time zone offset and it is UTC-7. So you apply that to some dates and times in your application and done - so you think. Except that you didn't take into account that the user is in California, and one of your dates is in December when the offset should be UTC-8.

So you try to correct for that, and work out the rules of "when I see -7, it might be -8 sometimes". Except now you have a user come along who is in Colorado, where it is -7 during the winter and -6 during the summer. Or another user from Arizona, where most of the state is in -7 for the whole year. How do you know which set of rules to follow? Without referencing an actual time zone, it cannot be done.

This gets even more complex worldwide. For example, the number of variations for UTC+2 is just crazy. Even for countries that switch between UTC+2 and UTC+3 - they don't all switch on the same dates or at the same time of day!

See also: The Problem with Time & Timezones - Computerphile (YouTube) and the StackOverflow timezone tag wiki.

Original Thread

By anonymous    2017-10-30

Kalip, if you mention the word "date", then the problem is way tougher than it looks, and so you have to use a library. More details about it here: https://www.youtube.com/watch?v=-5wpm-gesOY . However, if it is not about dates, but just about 2 measures in, lets say, a stopwatch device, then I would recommend to compute the total seconds for the first, the total of seconds for the second, subtract, then convert from seconds to hour minutes seconds the result again.

Original Thread

By anonymous    2017-10-30

new Date uses local time. So, you would be pointing to 1970-02-01, but you are in a local time GMT minus-something, and so you see the previous day, 1970-01-31. In my computer, as I'm in GMT +1, I see 1970-02-01. Check Date documentation and Date.UTC function. Dates are quite complicated... I recommend you to check also: https://www.youtube.com/watch?v=-5wpm-gesOY

Original Thread

By anonymous    2017-11-13

As Tom scott said in the [Computerphile video about timezone](https://www.youtube.com/watch?v=-5wpm-gesOY), you should always find a library that does that. i suggest momentJS function `moment().day()` that returns exaclty that.

Original Thread

By anonymous    2017-11-13

Brad is right datetime would be best in a professional setting. As any programmer has probably learned: https://www.youtube.com/watch?v=-5wpm-gesOY

Original Thread

By anonymous    2017-12-18

The overflow error is caused by the epoch time, being converted twice and reformatted and ended up being something that it couldn't handle. I've written an update for that. As for the time conversion to a local time which observes is actually quite difficult. [This video](https://www.youtube.com/watch?v=-5wpm-gesOY) explains it quite well.

Original Thread

By dbg31415    2017-11-21

* The Problem with Time & Timezones - Computerphile - YouTube || https://www.youtube.com/watch?v=-5wpm-gesOY

Original Thread

By anonymous    2017-11-27

I'd recommend using a library that deals with this type of thing exclusively. Moment.js is a very good one.

This video by Tom Scott beautifully explains the difficulty with dealing with time and date stuff yourself.

var myTime = moment.tz("2017-11-20 03:35 PM", "Asia/Karachi");
var myTimeUTC = myTime.clone().tz('UTC');

Original Thread

By anonymous    2018-01-14

Because language writing is harder than it looks, and handling time in particular is a lot harder than most people think. For a small part of the problem (in reality, not Java), see the YouTube video "The Problem with Time & Timezones - Computerphile" at https://www.youtube.com/watch?v=-5wpm-gesOY. Don't be surprised if your head falls off from laughing in confusion.

Original Thread

By anonymous    2018-01-14

But as NetMage said, if you have to deal with the timer overlowing AM, you propably have to use a full DateTime. It might even deal with TImezones and DST. Time formating, storing and measurement are not easy at all: https://www.youtube.com/watch?v=-5wpm-gesOY

Original Thread

Recommended Books

    Popular Videos 328

    Google Developers

    Submit Your Video

    If you have some great dev videos to share, please fill out this form.