RTC and TimeZones (shoot me now)

Discussion to talk about software related topics only.
Post Reply
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

RTC and TimeZones (shoot me now)

Post by sblair »

So I ventured into a new topic of implementing RTC (RealTimeClock) functionality in my product using the MOD54415.

Since I thought it would be smart to use NTP functionality to update my RTC chip on the occasions when I do have a inet connection this means I have to deal with setting TimeZones.

I deal with stuff that generally gets shipped worldwide so I adopted the TZ list from MS as a reasonable standard: https://msdn.microsoft.com/en-us/librar ... d.11).aspx

Since the NB prefers dealing with TZ using the POSIX TZ strings my current challenge is finding a clean list of all the POSIX TZ strings that I can use. Surprisingly I haven't actually found a decent one to use yet...probably because much of the world has moved to using the IANA TZ format it seems.

Any suggestions?

As a bonus for anyone that has dealt with code for TimeZones this is a brilliant and entertaining watch: https://www.youtube.com/watch?v=-5wpm-gesOY
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: RTC and TimeZones (shoot me now)

Post by dciliske »

Not sure about the different TZ formats. I'll have to take a look at this. Time to learn something new!

Also, that video is a fantastic rant! And the next video in YouTube's autoplay landed me with this: End of Time (Unix) - Numberphile. Yea... That one is on my list...

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

Re: RTC and TimeZones (shoot me now)

Post by sblair »

In an effort to save the next poor sap some trouble here is the table of TZ's I built. It was a fair bit of effort as I had to compile data from a number of sources. The list is based off the list of Microsoft supported TimeZones as being a common reference point for most people.

The astute observer will notice I left off the DST date change rules out of the Posix string. I figure those change too damn often to ever be right so I've taken the approach my car does and just provided a DST checkbox to indicate whether DST is currently active or not. If that TZ observes DST then it will use the DST offset info from the Posix string. If it doesn't observe DST then the DST checkbox setting has no effect.

FYI as I discovered the SetTimeZone() example code isn't really valid as it only deals with full hour offsets and not the nonsense of fractional hour offsets that exist in a number of places around the world.

There is also a bit of a bug it seems if you set the tm_isdst flag TRUE for a TZ that doesn't have a POSIX DST time in it. For example, if my TZ is "MST7" for Arizona, then when I set the DST flag on instead of doing an offset by an hour or keeping the same time (ideal) it does an offset by 7 hours which is nowhere near any kind of valid interpretation as it appears to just be picking GMT. The hack around this was just listing the tzchar for it as "MST7MST7" so there Standard tz is duplicated.

Code: Select all


													//TZ Abbreviations: http://www.timeanddate.com/time/zones/
													//TZ Posix from: http://community.ubnt.com/ubnt/attachments/ubnt/airMAX-General/36264/2/uclibc-zoneinfo.list.txt
s_TimeZones sTimeZones[]=							//From: https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx
{	//index, offset,  Posix String,			full description.                                                    	tz name,
	{	 00, -12 *60, "AoE12AoE12",			"(GMT-12:00) International Date Line West"},                         //"Dateline Standard Time",						// 0
	{	 01, -11 *60, "SST11SST11",			"(GMT-11:00) Midway Island, Samoa"},                                 //"Samoa Standard Time",                           // 1
	{	 02, -10 *60, "HST10HST10",			"(GMT-10:00) Hawaii"},                                               //"Hawaiian Standard Time",                        // 2
	{	 03, -9  *60, "AKST9AKDT8",			"(GMT-09:00) Alaska" },                                              //"Alaskan Standard Time",                         // 3
	{	 04, -8  *60, "PST8PDT7",			"(GMT-08:00) Pacific Time (US and Canada); Tijuana" },               //"Pacific Standard Time",                         // 4
	{	 10, -7  *60, "MST7MDT6",			"(GMT-07:00) Mountain Time (US and Canada)" },                       //"Mountain Standard Time",                        // 5
	{	 13, -7  *60, "MST7MDT6",			"(GMT-07:00) Chihuahua, La Paz, Mazatlan" },                         //"Mexico Standard Time 2",                        // 6
	{	 15, -7  *60, "MST7MST7",			"(GMT-07:00) Arizona" },                                             //"U.S. Mountain Standard Time",                   // 7
	{	 20, -6  *60, "CST6CDT5",			"(GMT-06:00) Central Time (US and Canada" },                         //"Central Standard Time",                         // 8
	{	 25, -6  *60, "CST6CST6",			"(GMT-06:00) Saskatchewan" },                                        //"Canada Central Standard Time",                  // 9
	{	 30, -6  *60, "CST6CST6",			"(GMT-06:00) Guadalajara, Mexico City, Monterrey" },                 //"Mexico Standard Time",                          // 10
	{	 33, -6  *60, "CST6CST6",			"(GMT-06:00) Central America" },                                     //"Central America Standard Time",                 // 11
	{	 35, -5  *60, "EST5EDT4",			"(GMT-05:00) Eastern Time (US and Canada)" },                        //"Eastern Standard Time",                         // 12
	{	 40, -5  *60, "EST5EST5",			"(GMT-05:00) Indiana (East)" },                                      //"U.S. Eastern Standard Time",                    // 13
	{	 45, -5  *60, "COT5COT5",			"(GMT-05:00) Bogota, Lima, Quito" },                                 //"S.A. Pacific Standard Time",                    // 14
	{	 50, -4  *60, "AST4ADT3",			"(GMT-04:00) Atlantic Time (Canada)" },                              //"Atlantic Standard Time",                        // 15
	{	 55, -4  *60, "VET4VET4",			"(GMT-04:00) Caracas, La Paz" },                                     //"S.A. Western Standard Time",                    // 16
	{	 56, -4  *60, "CLT4CLST3",			"(GMT-04:00) Santiago" },                                            //"Pacific S.A. Standard Time",                    // 17
	{	 60, -3.5*60, "NST3:30NDT2:30",		"(GMT-03:30) Newfoundland and Labrador" },                           //"Newfoundland and Labrador Standard Time",       // 18
	{	 65, -3  *60, "BRT3BRST2",			"(GMT-03:00) Brasilia" },                                            //"E. South America Standard Time",                // 19
	{	 70, -3  *60, "ART3ART3",			"(GMT-03:00) Buenos Aires, Georgetown" },                            //"S.A. Eastern Standard Time",                    // 20
	{	 73, -3  *60, "EGT1EGST0",			"(GMT-03:00) Greenland" },                                           //"Greenland Standard Time",                       // 21
	{	 75, -2  *60, "MAT2MADT1",			"(GMT-02:00) Mid-Atlantic" },                                        //"Mid-Atlantic Standard Time",                    // 22
	{	 80, -1  *60, "AZOT1AZOST0",		"(GMT-01:00) Azores" },                                              //"Azores Standard Time",                          // 23
	{	 83, -1  *60, "CVT1CVT1",			"(GMT-01:00) Cape Verde Islands" },                                  //"Cape Verde Standard Time",                      // 24
	{	 85,  0  *60, "GMT0IST-1",			"(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London" },    //"GMT Standard Time",                             // 25
	{	 90,  0  *60, "WET0WET0",			"(GMT) Casablanca, Monrovia" },                                      //"Greenwich Standard Time",                       // 26
	{	 95,  1  *60, "CET-1CEST-2",		"(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague" },   //"Central Europe Standard Time",                  // 27
	{	100,  1  *60, "CET-1CEST-2",		"(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb" },                    //"Central European Standard Time",                // 28
	{	105,  1  *60, "CET-1CEST-2",		"(GMT+01:00) Brussels, Copenhagen, Madrid, Paris" },                 //"Romance Standard Time",                         // 29
	{	110,  1  *60, "CET-1CEST-2",		"(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna" },    //"W. Europe Standard Time",                       // 30
	{	113,  1  *60, "WAT-1WAT-1",			"(GMT+01:00) West Central Africa" },                                 //"W. Central Africa Standard Time",               // 31
	{	115,  2  *60, "EET-2EEST-3",		"(GMT+02:00) Bucharest" },                                           //"E. Europe Standard Time",                       // 32
	{	120,  2  *60, "EET-2EEST-3",		"(GMT+02:00) Cairo" },                                               //"Egypt Standard Time",                           // 33
	{	125,  2  *60, "EET-2EEST-3",		"(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius" },       //"FLE Standard Time",                             // 34
	{	130,  2  *60, "EET-2EEST-3",		"(GMT+02:00) Athens, Istanbul, Minsk" },                             //"GTB Standard Time",                             // 35
	{	135,  2  *60, "IST-2IDT-3",			"(GMT+02:00) Jerusalem" },                                           //"Israel Standard Time",                          // 36
	{	140,  2  *60, "CAT-2CAT-2",			"(GMT+02:00) Harare, Pretoria" },                                    //"South Africa Standard Time",                    // 37
	{	145,  3  *60, "MSK-3MSD-4",			"(GMT+03:00) Moscow, St. Petersburg, Volgograd" },                   //"Russian Standard Time",                         // 38
	{	150,  3  *60, "AST-3AST-3",			"(GMT+03:00) Kuwait, Riyadh" },                                      //"Arab Standard Time",                            // 39
	{	155,  3  *60, "EAT-3EAT-3",			"(GMT+03:00) Nairobi" },                                             //"E. Africa Standard Time",                       // 40
	{	158,  3  *60, "AST-3ADT-4",			"(GMT+03:00) Baghdad" },                                             //"Arabic Standard Time",                          // 41
	{	160,  3.5*60, "IRT-3:30IRST-4:30",	"(GMT+03:30) Tehran" },                                              //"Iran Standard Time",                            // 42
	{	165,  4  *60, "GST-4GST-4",			"(GMT+04:00) Abu Dhabi, Muscat" },                                   //"Arabian Standard Time",                         // 43
	{	170,  4  *60, "AZT-4AZST-5",		"(GMT+04:00) Baku, Tbilisi, Yerevan" },                              //"Caucasus Standard Time",                        // 44
	{	175,  4.5*60, "AFT-4:30AFT-4:30",	"(GMT+04:30) Kabul" },                                            	 //"Trans. Islamic State of Afghanistan Std Time"   // 45
	{	180,  5  *60, "YEKT-5YEKST-6",		"(GMT+05:00) Ekaterinburg" },                                        //"Ekaterinburg Standard Time",                    // 46
	{	185,  5  *60, "PKT-5PKT-5",			"(GMT+05:00) Islamabad, Karachi, Tashkent" },                        //"West Asia Standard Time",                       // 47
	{	190,  5.5*60, "IST-5:30IST-5:30",	"(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi" },                 //"India Standard Time",                           // 48
	{	191,  5.5*60, "SLST-5:30SLST-5:30",	"(GMT+05:30) Sri Jayawardenepura" },                                 //"Sri Lanka Standard Time",                       // 49
	{	193,  5.75*60,"NPT-5:45NPT-5:45",	"(GMT+05:45) Kathmandu" },                                           //"Nepal Standard Time",                           // 50
	{	195,  6  *60, "BDT-6BDT-6",			"(GMT+06:00) Astana, Dhaka" },                                       //"Central Asia Standard Time",                    // 51
	{	201,  6  *60, "ALMT-6ALMST-7",		"(GMT+06:00) Almaty, Novosibirsk" },                                 //"N. Central Asia Standard Time",                 // 52
	{	203,  6.5*60, "MMT-6:30MMT-6:30",	"(GMT+06:30) Yangon Rangoon" },                                      //"Myanmar Standard Time",                         // 53
	{	205,  7  *60, "ICT-7ICT-7",			"(GMT+07:00) Bangkok, Hanoi, Jakarta" },                             //"S.E. Asia Standard Time",                       // 54
	{	207,  7  *60, "KRAT-7KRAST-8",		"(GMT+07:00) Krasnoyarsk" },                                         //"North Asia Standard Time",                      // 55
	{	210,  8  *60, "CST-8CST-8",			"(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi" },           //"China Standard Time",                           // 56
	{	215,  8  *60, "SGT-8SGT-8",			"(GMT+08:00) Kuala Lumpur, Singapore" },                             //"Singapore Standard Time",                       // 57
	{	220,  8  *60, "CST-8CST-8",			"(GMT+08:00) Taipei" },                                              //"Taipei Standard Time",                          // 58
	{	225,  8  *60, "WST-8WST-8",			"(GMT+08:00) Perth" },                                               //"W. Australia Standard Time",                    // 59
	{	227,  8  *60, "ULAT-8ULAT-8",		"(GMT+08:00) Irkutsk, Ulaanbaatar" },                                //"North Asia East Standard Time",                 // 60
	{	230,  9  *60, "KST-9KST-9",			"(GMT+09:00) Seoul" },                                               //"Korea Standard Time",                           // 61
	{	235,  9  *60, "JST-9JST-9",			"(GMT+09:00) Osaka, Sapporo, Tokyo" },                               //"Tokyo Standard Time",                           // 62
	{	240,  9  *60, "YAKT-9YAKST-10",		"(GMT+09:00) Yakutsk" },                                             //"Yakutsk Standard Time",                         // 63
	{	245,  9.5*60, "CST-9:30CST-9:30",	"(GMT+09:30) Darwin" },                                              //"A.U.S. Central Standard Time",                  // 64
	{	250,  9.5*60, "CST-9:30CST-10:30",	"(GMT+09:30) Adelaide" },                                            //"Cen. Australia Standard Time",                  // 65
	{	255, 10  *60, "EST-10EST-11",		"(GMT+10:00) Canberra, Melbourne, Sydney" },                         //"A.U.S. Eastern Standard Time",                  // 66
	{	260, 10  *60, "EST-10EST-10",		"(GMT+10:00) Brisbane" },                                            //"E. Australia Standard Time",                    // 67
	{	265, 10  *60, "EST-10EST-11",		"(GMT+10:00) Hobart" },                                              //"Tasmania Standard Time",                        // 68
	{	270, 10  *60, "VLAT-10VLAST-11",	"(GMT+10:00) Vladivostok" },                                         //"Vladivostok Standard Time",                     // 69
	{	275, 11  *60, "ChST-10ChST-10",		"(GMT+10:00) Guam, Port Moresby" },                                  //"West Pacific Standard Time",                    // 70
	{	280, 11  *60, "MAGT-11MAGST-12",	"(GMT+11:00) Magadan, Solomon Islands, New Caledonia" },             //"Central Pacific Standard Time",                 // 71
	{	285, 12  *60, "FJT-12FJT-12",		"(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands" },           //"Fiji Islands Standard Time",                    // 72
	{	290, 12  *60, "NZST-12NZDT-13",		"(GMT+12:00) Auckland, Wellington" },                                //"New Zealand Standard Time",                     // 73
	{	300, 13  *60, "TOT-13TOT-13",		"(GMT+13:00) Nuku'alofa" },                                          //"Tonga Standard Time",                           // 74
};

User avatar
pbreed
Posts: 1088
Joined: Thu Apr 24, 2008 3:58 pm

Re: RTC and TimeZones (shoot me now)

Post by pbreed »

Wow thanks for all that work, is it ok to copy and include your work in the netburner examples?

As for our old friend :
>SetTimeZone()

This function had been removed from the latest examples in our source system before this topic poped up on the group.
It will be in the next beta the expectation is that tzsetchar will be used instead or SetTimezone.

SetTimezone is modified to be depricated and work correctly with tzsetchar.. the old way was broken.

This was an error induced when the developer doing the file system did not realize tzsetchar existed.

Paul
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

Re: RTC and TimeZones (shoot me now)

Post by sblair »

Sure Paul. You're absolutely welcome to use it! I would suggest including the websites I had in there too as it took quite a while to find sites that actually had useful information.

I'm glad I chose the tzchar() for doing the offsets. I would suggest fixing the tzchar() function to handle non-DST zones though so you don't have to have Posix entries like "MST7MST7" which is how I hacked around the issue so I could set the tm_isdst flag myself. I went ahead and logged #34294 for this earlier today.
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

Re: RTC and TimeZones (shoot me now)

Post by sblair »

Paul,

What kind of time drift do you typically see from the PCF8563? I'm noticing that I'm getting about a 6-7 second drift just overnight of it running fast.

Here's my test scenario. When I power up I check for an NTP server. If I can connect to one then I update SystemTime and then update the RTC using: RTCSetRTCfromSystemTime(); I will then power cycle with NTP access disconnected and observe that the RTC chip is accurate to within ~1 second of my computer. So I know the RTC chip is updated and it is accurate as a starting point.

Overnight I'll leave it and notice the SystemTime drift. So I added logic once per hour to call RTCSetSystemFromRTCTime(); to re-sync system time to RTC time. Overnight I'm still seeing it drift by about 7 seconds. I can then power cycle with NTP access removed and it still comes up ~7 seconds off so I know that it is the RTC chip itself that is drifting.

Any thoughts? Attached is my RTC schematic. The only access I have done to the RTC chip as been through the above library calls.

Thanks!
Scott

RTC.JPG
RTC.JPG (42.15 KiB) Viewed 8039 times
mbrown
Posts: 61
Joined: Tue Jan 29, 2013 7:12 pm

Re: RTC and TimeZones (shoot me now)

Post by mbrown »

This one comes down to the accuracy of your input clock. We've gone through the numbers on this a few times, but what it boils down to is the most accurate you can be is determined by your frequency and the accuracy of that frequency. Since you're using a pretty standard RTC, the frequency can't really change much, 32.768kHz. The crystal we use is 20ppm.

The magic formula you're looking for, that quantifies guarantee-able accuracy is drift = time measured * variation (variation = freq * stability) / Frequency.

So in one day you'd expect in our case

drift = ((24hrs*60min/hr*60sec/min) * (32768 Hz *20/1,000,0000))/(32768Hz) = 1.728

So the maximum drift you could expect from a 32.768kHz crystal with that 20ppm accuracy is 1.728 seconds lost or gained per day.

We ran into much the same problem you were having. Our accuracy was pretty bad, usually on the 6-7 secs per day order or worse. Essentially what we ended up needing to do is crystal tuning. Just take a google search cystal selection and tuning with and without respect to real time clocks and you'll find a number of good articles on the subject. If you want a quick an dirty sort of approximation of what you might need, as long as your crystal routing is pretty clean, your schematic matches ours as long as you change C24 to be a stuffed 24pF cap. Once we had a better value, we ended up not even coming near that 1.728 value above, but again, the value we calculated above is the accuracy value you can guarantee from that oscillator. It may get closer most of the time, but you can't guarantee anything better based on the specs.
sblair
Posts: 162
Joined: Mon Sep 12, 2011 1:54 pm

Re: RTC and TimeZones (shoot me now)

Post by sblair »

Thanks. I'm using a 20ppm crystal here too. Looks like it just needs tuning for the circuit. As I was reading through the RTC datasheet I had a feeling it was going to be down to the clock circuit.
Post Reply