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 (34):

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

By anonymous    2018-01-22

The whole point of UTC is that you can leave including the Timezone of the users computer to the ToString() function being called. And everytime else you work with a Unambigious value. You **really** do not want to manually handle timezones, ever: https://www.youtube.com/watch?v=-5wpm-gesOY "That way lies madness".

Original Thread

By anonymous    2018-02-05

Like Tom scott said in [his video](https://www.youtube.com/watch?v=-5wpm-gesOY). You should use a librairy

Original Thread

By anonymous    2018-02-05

I have a number of hard and fast rules for dealing with DateTimes:

  • Always store, retrieve and transmit the UTC value. You do not want to deal with Timezones. That way lies madness
  • Avoid storing, retrieving or transmitting them as Strings.
  • If you can not avoid store/retreive/transmit as string, pick a fixed String Encoding and Format at all ends

If you follow all those rules you can somewhat reasonably work with DateTimes without going mad.

If you can not follow those rules, you should simply call it impossible so you can enforce the rules with a proper rework of the faulty code.

Original Thread

By anonymous    2018-02-05

Does your time zone use day light saving time? You can [get in trouble by working dates by hand](https://www.youtube.com/watch?v=-5wpm-gesOY), better be careful on what happen on those edge cases.

Original Thread

By anonymous    2018-02-12

You era now dealing with Dates, Timeszones and internationalsiation now. American and Brits can not even agree at wich **day** the week starts on, wich makes this whole question a tangeled mess. My only advice? Most of the functions relating to dates do use the current Windows Format selection. Wich might include that data. Aside from that ideal case I would jsut never touch those thematics: https://www.youtube.com/watch?v=-5wpm-gesOY https://www.youtube.com/watch?v=0j74jcxSunY

Original Thread

By anonymous    2018-02-12

If you get ony 2 digits for the Year, tehre is no way to figure out if they mean 1901, 2001, 9001 or 0001. That is literally the reason the Y2k Bug was a big thing back in the day.

I have 3 basic rules for working with Datatimes:

  1. Always store, retrieve and Transmit the UTC value. You do not want to add timezones to your troubles.
  2. Avoid storage, retrieval or transmission as Text/string. If there is a proper datatype to use, use it.
  3. In the case where you can not fulfill point 2, pick a fixed Culture Format and String Encoding at all Endpoints. You do not want to add that madness too your troubles.

Naturally the culture format should carry all digits of the year. Because otherwise we have issues like yours.

Original Thread

By anonymous    2018-02-12

@Fratyx correct. Dates and times are far more complicated then most people realize. When introducing string representations it gets worst. When dealing with multiple cultures it's even harder, and it's even worst then that when you need to handle historical data or daylight savings time. I think the best approach in these cases is to limit your customer to a strict rule set - otherwise you might find yourself [going crazy.](https://www.youtube.com/watch?v=-5wpm-gesOY)

Original Thread

By anonymous    2018-02-18

I have 3 basic rules about handling DateTimes:

  1. Always store, transmit and retreive (STR) the UTC value. If you have a client application, it can translate that into the current Computers timezone (retreived from Windows). You really do not want to mess with Timezones. And only with WebServers will you ever have too.
  2. Avoid STR in string format.
  3. If you can not avoid STR in string, at least pick a fixed Culture Format and String encoding at all endpoints. You do not want to eitehr of those added to your problems.

If you follow those rules, the actuall processing becomes easy:

DateTime dueTime //set someplace else

if(DateTime.Now.AddMonth(-1) >= dueTime)
  //Due time is in one month or less

Original Thread

By anonymous    2018-03-05

Don't. DateTime values should be stored as DateTime, unless you have a really good reason for storing them otherwise (like for supporting date and time values outside of the min/max values of DateTime), I would suggest to should leave it in a DateTime column.

You can always manipulate how you return them from the database during Select or in the presentation layer. To return the unix time from DateTime, MySql provides a built in method called UNIX_TIMESTAMP. To return the number of milliseconds, simply multiply by 1000, since the unix timestamp is the number of seconds since January 1st, 1970 (not including leap seconds). If you want to store unix time, you will have to use an int data type.

Please note that if you do store unix time instead of storing the actual DateTime value in a DateTime data type column, you will loose the ability to use all the datetime built in database functions easily. For instance, if you want to find out how many rows belong to a specific month, you will first have to translate the data from int to datetime, and only then you will be able to calculate that.

You will also lose accuracy (since unix time is inaccurate even on the 1 second resolution, because it ignores leap seconds).

So, to conclude - When the database offers you a data type that fits the data, don't go storing that data using a different data type. use the Date data type if you only want to store dates, the DateTime data type if you want to store datetime values, and the Time data type if you want to store a specific time in the day.

P.S.
When dealing with date time values, Especially if you have to deal with clients from multiple locations, ALWAYS store only UTC date times in your database, unless, of course, you want to go mad.

Original Thread

By anonymous    2018-03-12

I have 3 basic Rules regarding DateTimes:

  1. Always store, transmit and retrieve UTC. Timezones? That is something .NET can deal with during output. After it asked Windows wich Timezone and Culture Format should be applied to that UTC value. You do not deal with Timezones, because that way lies madness.
  2. Avoid storage, transmission and retreival as strings. Use DateTime types for as long as possible.
  3. If you can not fullfill Rule 2 (XML or other Serialstion), at least pick a fixed culture and String Encoding at all Endpoints. You do not want to add those headaches to your issues.

In your case asuming you followed rule 1 and this is not a Server Application, just wait for Windows to Update it's Timezone/UST list. It is a UI job and .NET has very good connections to the Windows Systems responsible for this kind of stuff.

If this is a Server Application, each user can pick their own timezones. A minor change might be nesseary here. It really depends how you went about Internationalsiation.

Original Thread

By anonymous    2018-03-18

I have 3 rules for dealing with DateTimes that served me well:

  1. Always store, retreive and transmit the UTC value. Translating into the proper local Timezone is the job of ToString(), wich asks Windows for the users timezone. You do not want to add timezones to your troubles.
  2. Avoid store, retreive or transmission of DateTimes as strings. Keep it in proper types whenever possible
  3. If you can not follow rule 2 (like when you deal with Serialsiation), at least pick a fixed Culture Format and String encoding on all endpoints. You do not want to get different Cultures or faulty implied Encodings to your existing troubles

Original Thread

By anonymous    2018-03-26

I have a few general rules regarding handling DateTimes:

  1. Always store, retrieve and transmit the value in UTC. Windows is pretty good at translating any UTC value to whatever the current user picked as his favourite timezone. You do not want to deal with Timezones if you can avoid it at all.
  2. Never store, retrieve and transmit the value as string.
  3. In case 3 can not work, at least pick a fixed culture and string encoding at all endpoints. You do not want to add those to your worries.
  4. In rare cases (Callendar Apps) it might be beneficial to store the "originally saved timezone".

Original Thread

By anonymous    2018-05-01

"Times have to be stored in local". I'm really sorry for you. This right there is [the gate to madness.](https://www.youtube.com/watch?v=-5wpm-gesOY) Having to deal with daylight savings only makes the trip to madness faster. Please, take the advice of someone that have walked this road before, and for your own sanity - reconsider that approach.

Original Thread

By anonymous    2018-05-14

Mandatory watching before you start to implement a quick fix for your timezone problem: https://www.youtube.com/watch?v=-5wpm-gesOY

Original Thread

By anonymous    2018-05-29

I would suggest using momentJs for any kind of date manipulation. Tom Scott could explain you why here. Anyway, for your particular case, there is a moment-angular library that could be use as such :

/* controller declaration */.('$scope', 'moment', function($scope, moment) {
    $scope.isDateBefore = function(firstDate, secondDate) {
        return moment(firstDate).isBefore(secondeDate);
    }
})


<small 
    ng-show="isDateBefore(formStep1.expiry_date.$modelValue, formStep1.hiring_date.$modelValue)"
class="errorMsg ">

You can learn more about the isBefore function on the official momentjs doc

Original Thread

By anonymous    2018-07-02

Aside from the fact that you are missing a constructor, what you are trying to do is a horrible idea. The design is too rigid. It would be better to model days, monthis and years as separate objects and then use composition to model a date object. Or use [the java time API](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html), because [dates are a pain in the a**](https://www.youtube.com/watch?v=-5wpm-gesOY).

Original Thread

Popular Videos 574

Submit Your Video

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