Determining Local Time in another Timezone - perl

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').

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');

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.

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.

Related

Converting timestamps in Perl

I am looking to convert timestamps such as the following
2019-01-01T02:15:00+00:00
Into Australian Eastern Standard Time in Perl.
I have over 10,000 of these timestamps, any help would be really appreciated
I need to input them into a mysql DB with a format of YYYY-MM-DD hh:mm:ss
You would use the standard Perl module Time::Piece. It provides the standard strptime and strftime functions. The first allows you to parse a timestamp with a template and the second outputs a timestamp based on the same kind of template. To change timezones you would add or subtract the number of seconds difference.
$t = Time::Piece->strptime("2020-11-04T01:46:00", "%Y-%m-%dT%H:%M:%S");
$t += $offset;
print $t->strftime("%Y-%m-%dT%H:%M:%S");
Or if your current time is the current locale and you're always converting from GMT:
$t = Time::Piece->strptime("2020-11-04T01:46:00", "%Y-%m-%dT%H:%M:%S");
$l = localtime $t->epoch;
print $l->strftime("%Y-%m-%dT%H:%M:%S");
Now if you need to do something more complicated than that (daylight savings time, leap seconds), there is the DateTime module but it is correspondingly far more complicated to use.
See also How can I parse dates and convert time zones in Perl?
HTH

Determine Daylight Savings status for different time zone in Powershell

Is there a slick way in PowerShell to ascertain if a past date in another time zone is Daylight Savings or not? Here is the situation, our database is in Europe and the times and dates are local to that server. Since Europe and America start and stop DST at different times, i need to take into account the hour difference for those times.
Thanks for your advice.
There is no need to try to determine whether DST is in effect or not. Just let the .NET Framework do the conversion for you.
First, decide which time zone IDs you are converting from and to.
You said your input time was in Europe, but you didn't specify exactly where. Like the US, Europe has multiple time zones. I'll assume you meant CET/CEST (UTC+1/+2). In Windows, you can use any of the following identifiers for this:
"Central Europe Standard Time"
"Central European Standard Time"
"Romance Standard Time" (why? who knows.)
"W. Europe Standard Time" (don't get fooled by the name, it's still central)
These are all the same (in Windows) except for their display names. If you want to be precise in which one you pick, refer to the CLDR reference.
For the US Central time zone, use "Central Standard Time".
Then just use the TimeZoneInfo.ConvertTimeBySystemTimeZoneId function, as follows:
# collect your input (through db, or whatever mechanism you have)
$inputDateTime = Get-Date -Date "2017-06-27 00:00:00"
# pick your time zones
$fromTimeZone = "Central Europe Standard Time" # EU
$toTimeZone = "Central Standard Time" # USA
# convert
$outputDateTime = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId(
$inputDateTime, $fromTimeZone, $toTimeZone)
# output
Write-Output $outputDateTime
I know this is an older thread, but I actually needed to be able to determine whether or not it's DST currently. We have a server whose local TZ is set to UTC (which doesn't see DST) and have an automation that needs to be able to know when it's 4pm local time. So the script is all in UTC, but I can then add an hour or not based on the value of the result of this beast:
$DST = ([System.TimeZoneInfo]::ConvertTimeFromUtc(
(get-date).ToString(),
[System.TimeZoneInfo]::FindSystemTimeZoneById("Central Standard Time")
)).isdaylightsavingtime()
Cole, I love the inspiration as your response was a needle in a haystick and just what I needed. However, it produced an error. After some messing around, I got the following to work:
$isDST = ([System.TimeZoneInfo]::ConvertTimeFromUtc((Get-Date).ToUniversalTime(), [System.TimeZoneInfo]::FindSystemTimeZoneById("Central Standard Time"))).IsDaylightSavingTime()
(in PowerShell v4)

strftime '%z', (localtime) is not working as expected in solaris machines

I tried this code in linux machines,
my $sysdate = strftime "%Y%m%d%T", (localtime);
my $daylight_saving_time = strftime '%z', (localtime);
i get below output,
sysdate = 2013051402:12:02
daylight_saving_time = -0400
I tried same in solaries machines, i got this
sysdate = 2013051402:12:02
daylight_saving_time = %z
Anyone know the change to be done to get the daylight saving in solaries machines.
Thanks in Advance.
The issue is that POSIX::strftime just calls your system's strftime(3), so
you get whatever that is - or - is not. %z is not part of the POSIX.1 standard
and is not consistent across systems. On other older versions of OSes, like HPUX, %z, is
the same as %Z (time zone name). This is only for older versions.
On Solaris 8, 9 strftime does not support %z - with Solaris 10 it does.
This holds on more moderns versions Solaris 10 & Solaris 11:
%z Replaced by offset from UTC in ISO 8601:2000 standard format
(+hhmm or -hhmm), or by no characters if no time zone is deter-
minable. For example, "-0430" means 4 hours 30 minutes behind UTC
(west of Greenwich). If tm_isdst is zero, the standard time off-
set is used. If tm_isdst is greater than zero, the daylight sav-
ings time offset if used. If tm_isdst is negative, no characters
are returned.
So, this a C library function issue, perl sits on top of those libraries. I do not have a workaround.
Maybe the Date::Manip::TZ works on Solaris:
use Date::Manip::TZ;
my $tz = new Date::Manip::TZ;
say "tz: $tz";

How can I use Perl to do datetime comparisons and calculate deltas?

I extracted year, month, day, hour, minute, second, and millisecond data from human readable text (it wasn't in a timestamp format, but rather something like "X started at HH:MM:SS.SSS on DD MMM YYYY and ended at HH:MM:SS.SSSS on DD MMM YYYY"), so for each recorded event, I have each of the values.
However, I need to turn those into some kind of timestamp so I can do math on it - I want to determine how long the event lasted (end time - start time). I was hoping the time function would take parameters so I can create two arbitrary times, but that doesn't appear to be the case.
If possible, I would like to stick with functions available in the core Perl libraries or scripts that I can add to the project, since getting CPAN modules installed on the target machines would just make a headache for everyone, if it is even possible to get the modules through the security restrictions.
You want the CPAN module DateTime. Here's an introduction.
On a Debian GNU/Linux or Ubuntu system, simply run:
apt-get install libdatetime-perl
to install the module.
You can do it with Time:Local. It's basically the reverse of the built in "localtime" function, so you can generate a timestamp from a standard date.
In terms of built-ins these may be helpful:
POSIX (for mktime and strftime)
Time::Piece, Time::Local and Time::Seconds. These are all standard in Perl 5.10, but may not be available by default on earlier systems.
That said, time/date calculations are complex. If the only obstacle is a few headaches installing modules (rather than a company policy forbidding them), I would really recommend looking at CPAN.
Edit: I see from your comment on another post that there are company restrictions. You should update your original post, since there's a big difference between "headaches" and "security restrictions." In any case, DateTime and Date::Manip are worth looking at. Even if you don't install them, you can get a lot out of reading their source.
If you were only interested in comparing times,
my $ts1 = sprintf( '%4.4d%2.2d%2.2d%2.2d%2.2d%3.3d',
$year1, $month1, $mday1, $hour1, $min1, $sec1, $ms1 );
to
my $ts2 = sprintf( '%4.4d%2.2d%2.2d%2.2d%2.2d%3.3d',
$year2, $month2, $mday2, $hour2, $min2, $sec2, $ms2 );
using cmp would be sufficient.
To do arithmetic on these times, use Time::Local to get seconds since epoch and then add the $ms1/1000 to that value.
my $time1 = timelocal($sec1, $min1, $hour1, $mday1, $mon1, $year1) + $ms1/1000;
You can use POSIX::mktime to turn broken-up time into a timestamp. Be aware that the month is 0-based, and the year is 1900-based, so adjust accordingly. :-)
use POSIX qw(mktime);
$timestamp = mktime($sec, $min, $hour, $day, $month - 1, $year - 1900);

What's the opposite of the localtime function in Perl?

In Perl, localtime takes a Unix timestamp and gives back year/month/day/hour/min/sec etc. I'm looking for the opposite of localtime: I have the parts, and I'd like to build a unix timestamp from them.
You can use the timelocal function in the Time::Local CPAN module.
NAME
Time::Local - efficiently compute time
from local and GMT time
SYNOPSIS
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
$time = timegm($sec,$min,$hour,$mday,$mon,$year);
DESCRIPTION
This module provides functions that
are the inverse of built-in perl
functions localtime() and gmtime().
They accept a date as a six-element
array, and return the corresponding
time(2) value in seconds since the
system epoch (Midnight, January 1,
1970 GMT on Unix, for example). This
value can be positive or negative,
though POSIX only requires support for
positive values, so dates before the
system's epoch may not work on all
operating systems.
It is worth drawing particular
attention to the expected ranges for
the values provided. The value for the
day of the month is the actual day (ie
1..31), while the month is the number of months since January (0..11). This
is consistent with the values returned
from localtime() and gmtime().
Note: POSIX::mktime is a just a wrapper around your C library's mktime() function. Time::Local is a pure-Perl implementation, and always returns results matching Perl's localtime. Also, Time::Local offers gmtime, while mktime only works in local time. (Well, you could try changing $ENV{TZ}, but that doesn't work on some systems.)
POSIX::mktime
DateTime on CPAN might of of some use. It also has a lot of time manipulation/translation methods.
Just create the DateTime using your parts and call $datetime->formatter("%s") ;