How can I change the timezone of Log4perl timestamps - perl

My web server is in a timezone different from mine and I am using this pattern layout in the Log4perl config:
log4perl.appender.LOGFILE.layout=PatternLayout
log4perl.appender.LOGFILE.layout.ConversionPattern=%d | %p | %l | %c | %m%n
The %d produces a date/time in the timezone of the server. How can I make it log the date/time in my local timezone instead?
I am aware that the following:
$Log::Log4perl::DateFormat::GMTIME = 1;
Causes date/time to be logged in GMT however I could find nothing in the documentation to support arbitrary timezones.

If you set the time zone for Perl in general, that will fix the logs, too. Might be too blunt an instrument for your purposes:
use POSIX qw(tzset);
$ENV{TZ} = 'desired time zone goes here';
tzset;
To go even blunter, if you have access, you can set TZ in the environment of the web server itself and have everything in the desired zone.
But I think you're better off logging everything in UTC.

Related

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)

Error parsing time-zone with Time::Piece

Executing a simple Perl script
use Time::Piece;
my $t = Time::Piece->strptime('08:00 PM AST', "%I:%M %p %Z");
I got the following error: Error parsing time at /usr/local/lib/perl5/Time/Piece.pm line 469.
Is this a bug in the library or there is something wrong with the above code? When I remove AST time-zone from the input string, it works, but when time-zone is left, it fails.
I don't know what exact time-zone will be in input string, so I cannot adjust that part on my end. AST (see Wikipedia) is a proper abbreviation for Atlantic Time Zone, so it should work. But it does not!
The time zone field is ambiguous and cannot be parsed. For instance, CST is the abbreviation for China Standard Time, Central Standard Time, and Cuba Standard Time.
The module documentation says that the strptime method is from FreeBSD, where the %Z format accepts either the local time zone or GMT and nothing else. This may be true of strptime, but I can confirm only that, where I am located, GMT is acceptable while UTC and AST are not.
The solution I would recommend is to preprocess your time strings, replacing the time zone abbreviation with an unambiguous time zone offset. For instance AST (assuming you meant Atlantic Standard Time and not Arabia Standard Time) would be replaced with -0400, since it is four hours behind UTC. Then you can parse it with a %z format specifier and get the correct result.
use Date::Parse;
my $t = str2time('08:00 PM AST');

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 to get seconds of given timezone - UTC time in Perl

I have a file with lines of the form : 1311597859.567497 y_value_to_plot. The first token is time since epoch, i.e. unix time. The user wants to call plot_file.pl with this filename and a timezone specification such as "America/New_York" or "Europe/London". Calling gnuplot on this file with set xdata time; set timefmt "%s" works but it shows the hours in UTC time. But the user would like to see the local time. So for 1311597859.567497, without any timezone changes, gnuplot would show 12:44:19, but if the user specifies America/New_York, he would like to see 08:44:19 in the gnuplot window.
I though a simple fix would be to calculate the offset between utc and the given timezone and subtract that from the token, and then run new plot on this new file.
Hence I was looking for a way to get offset_seconds of UTC from a given timezone in Perl.
By unix time I assume you mean seconds since the epoch in local time and you are trying to convert to seconds since the epoch in UTC.
Consider using a module such as Time::Zone or DateTime::TimeZone (part of DateTime) to help with such a calculation.
For example with Time::Zone:
use Time::Zone;
my $offset_sec = tz_local_offset(); # or tz_offset($tz) if you have the TZ
# in a variable and it is not local
my $time = time(); # realistically it will be the time value you provide in localtime
my $utc_time = $time + $offset_sec;
With DateTime and DateTime::TimeZone:
use DateTime;
use DateTime::TimeZone;
# cache local timezone because determining it can be slow
# if your timezone is user specified get it another way
our $App::LocalTZ = DateTime::TimeZone->new( name => 'local' );
my $tz = DateTime::TimeZone->new( name => $App::LocalTZ );
my $dt = DateTime->now(); # again, time will be whatever you are passing in
# formulated as a DateTime
my $offset = $tz->offset_for_datetime($dt);
Note that using DateTime you can simply convert a DateTime object from local time to UTC time via set_time_zone('UTC') and then format it for gnuplot also.
To do it all by hand, you can format the output of gmtime if you can get to epoch seconds from your local time (perhaps using mktime out of a date/time string).

Determining Local Time in another Timezone

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.