2

How can I determine the current date and time of various countries using a PERL script that executes on a server in the US? For example, getDTnow() should determine the current date and time on the server and use that to return the date and time of various countries.

P.S: It would be great if this can be done using only the built-in functions, without any external modules.


Conclusion: Date maths is [use swear word here] complicated and easy to get wrong. Other perl gurus on IRC, groups and other parts of the net confirmed what Ether had been advicing me - use DateTime. DVK's solution is also pretty neat for those of you who don't mind messing with the perl environment. (Note: Though on windows, the caveats section of the Time::Piece docs says one should be careful while 'Setting $ENV{TZ} in Threads on Win32').

Sam
  • 1,358
  • 4
  • 16
  • 30
  • 3
    Regarding "without any external modules" -- you need to read ["But I can't use CPAN!"](http://www.shadowcat.co.uk/blog/matt-s-trout/but-i-cant-use-cpan/) – Ether Jan 11 '11 at 20:23
  • 1
    @Ether: Thanks for the link. It was an interesting read. I don't want to use any modules because I am learning perl. If a built-in function can do the simple task, why import a perl module that does a whole lot of other stuff that my script will never use? (Let's not forget TIMTOWTDI :). – Sam Jan 11 '11 at 20:41
  • 3
    time calculations are *not* simple, as there are lots of edge cases. If there is a module that has already taken care of the debugging and implementation of all the edge cases for you, you should use it, rather than attempting to reinvent the wheel. You can always pop the hood to learn how it is doing it -- the code is readily available for inspection. – Ether Jan 11 '11 at 21:39
  • 2
    part of learning Perl is learning CPAN. – CanSpice Jan 12 '11 at 01:04

3 Answers3

6

DateTime is a wonderful library that can use standard timezones to do everything you desire and more:

use DateTime;

# returns local time in Italy
my $dt = DateTime->now(time_zone => 'Europe/Rome');

# prints time in desired format
print "The current date and time in Italy is: ", $dt->strftime('%Y-%m-%d %T');
Ether
  • 53,118
  • 13
  • 86
  • 159
  • Yes, I am looking for something like this but I'd like to avoid using any modules. Is there anyway to do something similar with gmtime()? – Sam Jan 11 '11 at 20:33
  • @Sam: read the link I provided above. Avoiding using any modules is a fool's errand. – Ether Jan 11 '11 at 20:40
  • I am not averse to using a module. But I want to know if this can be done using any of the built-in functions. – Sam Jan 11 '11 at 20:52
3

You can control which timezone localtime returns in via TZ environmental variable:

local $ENV{TZ} = ":/usr/share/lib/zoneinfo/Asia/Tokyo";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(); 
print "$sec,$min,$hour,$mday,$mon,$year,$wday,$yday\n"'
# Prints 40,58,4,12,0,111,3,11

local $ENV{TZ} = ":/usr/share/lib/zoneinfo/Europe/London";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(); 
print "$sec,$min,$hour,$mday,$mon,$year,$wday,$yday\n"'
# Prints 41,58,19,11,0,111,2,10

Unfortunately, the path above is different on different Unixes (/usr/share/lib/zoneinfo on Solaris, /usr/share/zoneinfo on Linux). Since there appear to be no other variations, a slightly portable version would check which of the 2 directories exists and use that - but this obviously only works on Solaris and Linux and may be other unixes. No idea about Windows/MacOS/whatnot.

Valid locations for TZ can be found here: http://www.timezoneconverter.com/cgi-bin/tzref.tzc (but not all of them would necessarily be available on your system - check the above directory).

Please see http://en.wikipedia.org/wiki/Tz_database for more info on TZ database.

DVK
  • 126,886
  • 32
  • 213
  • 327
  • Wouldn't gmtime() be more appropriate than localtime() - one wouldn't have to meddle with the environment variables ... I am stuck on how to 'pass' it a timezone to get the date / time of that zone. – Sam Jan 11 '11 at 20:13
  • @Sam - I may have misunderstood you, but I thought "current date and time of various countries" you requested was the local time (which localtime returns). – DVK Jan 11 '11 at 20:20
  • @Sam - "How to pass the timezone" part was the `ENV{TZ}` assignment. – DVK Jan 11 '11 at 20:21
  • @DVK: Yes, I want the local time. I was seeking a clarification from you - can we avoid having to set the timezone through ENV{TZ} by using gmtime()? For example, can we do something like this. @now = gmtime(); @china = @now + $chinaOffset; @germany = @now + $germanyOffset ... and so on? Is there some other way to pass the timezone offset to gmtime directly? – Sam Jan 11 '11 at 20:30
  • 1
    Don't forget to adjust for daylight savings time! – Ether Jan 11 '11 at 20:51
  • @Sam - you can probably parse the timzeone database by hand. But that's **exactly** what `localtime` does!!! So, yes, you can re-implement localtime by hand, but why bother? – DVK Jan 11 '11 at 21:03
  • @Ether - doesn't localtime internal logic adjust for that? – DVK Jan 11 '11 at 21:05
  • Perldocs on gmtime() says there is no DST in GMT. From what I have read so far, apparentlly GMT / UTC takes 'care' of that. If anybody could shed some more light on that ... – Sam Jan 11 '11 at 21:06
  • 1
    @Sam: No, there isn't DST in UTC but there is DST in the local time. You'd also have to manually account for when DST is in effect and keep in mind that when DST takes effect (if at all!) depends on the location. Date wrangling is a horrific mess of special cases and foolish local conventions, the only things that rolling your own will do is produce bugs and teach you to never do it again. – mu is too short Jan 11 '11 at 23:33
  • Thanks mu. I think I am beginning to get what you and others mean. – Sam Jan 12 '11 at 17:40
0

You could always store the variation from your timezone in a hash where the key is the timezone and the value is the adjustment from the current time. then when you pass the current time it should return the local time for that zone.

Alos
  • 2,657
  • 5
  • 35
  • 47