Why `mktime()` unexpectedly ignores .tm_isdst for some timezones? - c

When using mktime(), the .tm_isdst member, when 0 or 1, results in a struct tm --> time_t difference of one 1 hour or the day light savings time shift for many zones such as America/ Los_Angeles.
This is as expected and consistent with most time-zones. For 2 struct tm that differ only in .tm_isdst = 0 or 1, the result of mktime() differ by the daylight shift.
With a few zones, including ones which employ daylight savings times, (e. g. America/Dawson_Creek) the mktime() result seems to ignore .tm_isdst for most struct tm times unless it is that one hour of that 25-hour day when going off daylight savings time.
1) Why do some timezones ignore .tm_isdst? (Even though they use DST) Perhaps I have missed something.
My opinion is that mktime() is broke for some minor zones that derive data from the major zones.
2) If indeed a gcc mktime() bug, what are the next steps?
Note: No issues seen when .tm_idst < 0.
System call mktime ignores tm_isdst flag does not apply here as the struct tm is refreshed before each mktime() call.
Output (Scroll down and notice the * * * lines)
time_t (and delta from previous) via various .isdst settings.
Unchanged after localtime(), -1 , 0 , 1
America/Los_Angeles
No trouble here, each delta goes up by 3600 or the one-time 0 for .isdst=0, .isdst=1
gmt:Sun Oct 25 05:30:00 1970 +0000 GMT 0
local:Sat Oct 24 22:30:00 1970 -0700 PDT 1
time_t:25680600,25680600 , 25680600 , 25684200 , 25680600 ,
gmt:Sun Oct 25 06:30:00 1970 +0000 GMT 0
local:Sat Oct 24 23:30:00 1970 -0700 PDT 1
time_t:25684200,25684200 3600, 25684200 3600, 25687800 3600, 25684200 3600,
gmt:Sun Oct 25 07:30:00 1970 +0000 GMT 0
local:Sun Oct 25 00:30:00 1970 -0700 PDT 1
time_t:25687800,25687800 3600, 25687800 3600, 25691400 3600, 25687800 3600,
gmt:Sun Oct 25 08:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0700 PDT 1
time_t:25691400,25691400 3600, 25695000 7200, 25695000 3600, 25691400 3600,
gmt:Sun Oct 25 09:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0800 PST 0
time_t:25695000,25695000 3600, 25695000 0, 25695000 0, 25691400 0,
gmt:Sun Oct 25 10:30:00 1970 +0000 GMT 0
local:Sun Oct 25 02:30:00 1970 -0800 PST 0
time_t:25698600,25698600 3600, 25698600 3600, 25698600 3600, 25695000 3600,
gmt:Sun Oct 25 11:30:00 1970 +0000 GMT 0
local:Sun Oct 25 03:30:00 1970 -0800 PST 0
time_t:25702200,25702200 3600, 25702200 3600, 25702200 3600, 25698600 3600,
Africa/Juba
Trouble here, delta goes up by 7200, .isdst seems only relevant for the one hour. else time_t same without regard to `.isdst.
gmt:Wed Oct 14 17:30:00 1970 +0000 GMT 0
local:Wed Oct 14 20:30:00 1970 +0300 CAST 1
time_t:24773400,24773400 , 24773400 , 24773400 , 24773400 ,
gmt:Wed Oct 14 18:30:00 1970 +0000 GMT 0
local:Wed Oct 14 21:30:00 1970 +0300 CAST 1
time_t:24777000,24777000 3600, 24777000 3600, 24777000 3600, 24777000 3600,
gmt:Wed Oct 14 19:30:00 1970 +0000 GMT 0
local:Wed Oct 14 22:30:00 1970 +0300 CAST 1
time_t:24780600,24780600 3600, 24780600 3600, 24780600 3600, 24780600 3600,
gmt:Wed Oct 14 20:30:00 1970 +0000 GMT 0
local:Wed Oct 14 23:30:00 1970 +0300 CAST 1
time_t:24784200,24784200 3600, 24784200 3600, 24787800 7200, 24784200 3600, ***
gmt:Wed Oct 14 21:30:00 1970 +0000 GMT 0
local:Wed Oct 14 23:30:00 1970 +0200 CAT 0
time_t:24787800,24787800 3600, 24784200 0, 24787800 0, 24784200 0,
gmt:Wed Oct 14 22:30:00 1970 +0000 GMT 0
local:Thu Oct 15 00:30:00 1970 +0200 CAT 0
time_t:24791400,24791400 3600, 24791400 7200, 24791400 3600, 24791400 7200, ***
gmt:Wed Oct 14 23:30:00 1970 +0000 GMT 0
local:Thu Oct 15 01:30:00 1970 +0200 CAT 0
time_t:24795000,24795000 3600, 24795000 3600, 24795000 3600, 24795000 3600,
America/Dawson_Creek
Trouble here, delta goes up by 7200, .isdst seems only relevant for the one hour. else time_t same without regard to `.isdst.
gmt:Sun Oct 25 05:30:00 1970 +0000 GMT 0
local:Sat Oct 24 22:30:00 1970 -0700 PDT 1
time_t:25680600,25680600 , 25680600 , 25680600 , 25680600 ,
gmt:Sun Oct 25 06:30:00 1970 +0000 GMT 0
local:Sat Oct 24 23:30:00 1970 -0700 PDT 1
time_t:25684200,25684200 3600, 25684200 3600, 25684200 3600, 25684200 3600,
gmt:Sun Oct 25 07:30:00 1970 +0000 GMT 0
local:Sun Oct 25 00:30:00 1970 -0700 PDT 1
time_t:25687800,25687800 3600, 25687800 3600, 25687800 3600, 25687800 3600,
gmt:Sun Oct 25 08:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0700 PDT 1
time_t:25691400,25691400 3600, 25695000 7200, 25695000 7200, 25691400 3600, ***
gmt:Sun Oct 25 09:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0800 PST 0
time_t:25695000,25695000 3600, 25695000 0, 25695000 0, 25691400 0,
gmt:Sun Oct 25 10:30:00 1970 +0000 GMT 0
local:Sun Oct 25 02:30:00 1970 -0800 PST 0
time_t:25698600,25698600 3600, 25698600 3600, 25698600 3600, 25698600 7200, ***
gmt:Sun Oct 25 11:30:00 1970 +0000 GMT 0
local:Sun Oct 25 03:30:00 1970 -0800 PST 0
time_t:25702200,25702200 3600, 25702200 3600, 25702200 3600, 25702200 3600,
America/Fort_Nelson
Trouble here, delta goes up by 7200, .isdst seems only relevant for the one hour. else time_t same without regard to `.isdst.
gmt:Sun Oct 25 05:30:00 1970 +0000 GMT 0
local:Sat Oct 24 22:30:00 1970 -0700 PDT 1
time_t:25680600,25680600 , 25680600 , 25680600 , 25680600 ,
gmt:Sun Oct 25 06:30:00 1970 +0000 GMT 0
local:Sat Oct 24 23:30:00 1970 -0700 PDT 1
time_t:25684200,25684200 3600, 25684200 3600, 25684200 3600, 25684200 3600,
gmt:Sun Oct 25 07:30:00 1970 +0000 GMT 0
local:Sun Oct 25 00:30:00 1970 -0700 PDT 1
time_t:25687800,25687800 3600, 25687800 3600, 25687800 3600, 25687800 3600,
gmt:Sun Oct 25 08:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0700 PDT 1
time_t:25691400,25691400 3600, 25695000 7200, 25695000 7200, 25691400 3600, ***
gmt:Sun Oct 25 09:30:00 1970 +0000 GMT 0
local:Sun Oct 25 01:30:00 1970 -0800 PST 0
time_t:25695000,25695000 3600, 25695000 0, 25695000 0, 25691400 0,
gmt:Sun Oct 25 10:30:00 1970 +0000 GMT 0
local:Sun Oct 25 02:30:00 1970 -0800 PST 0
time_t:25698600,25698600 3600, 25698600 3600, 25698600 3600, 25698600 7200, ***
gmt:Sun Oct 25 11:30:00 1970 +0000 GMT 0
local:Sun Oct 25 03:30:00 1970 -0800 PST 0
time_t:25702200,25702200 3600, 25702200 3600, 25702200 3600, 25702200 3600,
America/Punta_Arenas
Trouble here, delta goes up by 7200, .isdst seems only relevant for the one hour. else time_t same without regard to `.isdst.
gmt:Sat Mar 28 23:30:00 1970 +0000 GMT 0
local:Sat Mar 28 20:30:00 1970 -0300 -03 1
time_t: 7515000, 7515000 , 7515000 , 7515000 , 7515000 ,
gmt:Sun Mar 29 00:30:00 1970 +0000 GMT 0
local:Sat Mar 28 21:30:00 1970 -0300 -03 1
time_t: 7518600, 7518600 3600, 7518600 3600, 7518600 3600, 7518600 3600,
gmt:Sun Mar 29 01:30:00 1970 +0000 GMT 0
local:Sat Mar 28 22:30:00 1970 -0300 -03 1
time_t: 7522200, 7522200 3600, 7522200 3600, 7522200 3600, 7522200 3600,
gmt:Sun Mar 29 02:30:00 1970 +0000 GMT 0
local:Sat Mar 28 23:30:00 1970 -0300 -03 1
time_t: 7525800, 7525800 3600, 7529400 7200, 7529400 7200, 7525800 3600, ***
gmt:Sun Mar 29 03:30:00 1970 +0000 GMT 0
local:Sat Mar 28 23:30:00 1970 -0400 -04 0
time_t: 7529400, 7529400 3600, 7529400 0, 7529400 0, 7525800 0,
gmt:Sun Mar 29 04:30:00 1970 +0000 GMT 0
local:Sun Mar 29 00:30:00 1970 -0400 -04 0
time_t: 7533000, 7533000 3600, 7533000 3600, 7533000 3600, 7533000 7200, ***
gmt:Sun Mar 29 05:30:00 1970 +0000 GMT 0
local:Sun Mar 29 01:30:00 1970 -0400 -04 0
time_t: 7536600, 7536600 3600, 7536600 3600, 7536600 3600, 7536600 3600,
Test Code
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
// Some code to set the time zone
extern void tzset(void);
int set_tz(const char *tz) {
//tz = getenv("TZ");
//if (tz) {
printf("%s\n", tz);
if (setenv("TZ", tz, 1))
return 1;
tzset();
return 0;
}
// Print time info around the potential mistake
void time_oops(const char *tz, time_t t0, time_t t1) {
time_t before[4] = {0};
if (set_tz(tz)) {
return;
}
set_tz(tz);
for (time_t t = t0; t <= t1; t += 3600) {
char buf[200];
struct tm *tm = gmtime(&t);
strftime(buf, sizeof buf, "%c %z %Z", tm);
printf(" gmt:%-36s %d\n", buf, tm->tm_isdst);
tm = localtime(&t);
strftime(buf, sizeof buf, "%c %z %Z", tm);
printf("local:%-36s %d\n", buf, tm->tm_isdst);
printf("time_t:%8jd,", (intmax_t) t);
for (int dst = -2; dst <= 1; dst++) {
tm = localtime(&t);
if (dst > -2)
tm->tm_isdst = dst;
time_t t_make = mktime(tm);
printf("%8jd", (intmax_t) t_make);
if (t == t0) {
printf(" %5s, ", "");
} else {
printf(" %5jd, ", (intmax_t) (t_make - before[dst + 2]));
}
before[dst + 2] = t_make;
}
puts("");
}
}
// Run some tests
int main(void) {
int h = 60 * 60;
time_oops("America/Los_Angeles", 25662600 + 5 * h, 25662600 + 11 * h);
time_oops("Africa/Juba", 24784200 - 3 * h, 24784200 + 3 * h);
time_oops("America/Dawson_Creek", 25662600 + 5 * h, 25662600 + 11 * h);
time_oops("America/Fort_Nelson", 25687800 - 2 * h, 25687800 + 4 * h);
time_oops("America/Punta_Arenas", 7522200 - 2 * h, 7522200 + 4 * h);
return 0;
}
Some compiler output
make all
Building file: ../test.c
Invoking: Cygwin C Compiler
gcc -O0 -g3 -pedantic -Wall -Wextra -Wconversion -c -fmessage-length=0 -v -MMD -MP -MF"test.d" -MT"test.o" -o "test.o" "../test.c"
Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/gcc/gcc-7.3.0-3.x86_64/src/gcc-7.3.0/configure --srcdir=/cygdrive/i/szsz/tmpp/gcc/gcc-7.3.0-3.x86_64/src/gcc-7.3.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libcilkrts --enable-libgomp --enable-libitm --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
gcc version 7.3.0 (GCC)
COLLECT_GCC_OPTIONS='-O0' '-g3' '-Wpedantic' '-Wall' '-Wextra' '-Wconversion' '-c' '-fmessage-length=0' '-v' '-MMD' '-MP' '-MF' 'test.d' '-MT' 'test.o' '-o' 'test.o' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/cc1.exe -quiet -v -MMD test.d -MF test.d -MP -MT test.o -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api ../test.c -quiet -dumpbase test.c -mtune=generic -march=x86-64 -auxbase-strip test.o -g3 -O0 -Wpedantic -Wall -Wextra -Wconversion -version -fmessage-length=0 -o /cygdrive/c/Users/TPC/AppData/Local/Temp/cc3JcC90.s
GNU C11 (GCC) version 7.3.0 (x86_64-pc-cygwin)
compiled by GNU C version 7.3.0, GMP version 6.1.2, MPFR version 4.0.1-p6, MPC version 1.1.0, isl version isl-0.16.1-GMP
I used zdump to dump zone data yet found no difference for zones that work as expected and those that did not.
Some time zone data dump.
zdump -v /usr/share/zoneinfo/America/Los_Angeles
zdump -v /usr/share/zoneinfo/America/Dawson_Creek
/usr/share/zoneinfo/America/Los_Angeles Sun Apr 26 09:59:59 1970 UT = Sun Apr 26 01:59:59 1970 PST isdst=0 gmtoff=-28800
/usr/share/zoneinfo/America/Los_Angeles Sun Apr 26 10:00:00 1970 UT = Sun Apr 26 03:00:00 1970 PDT isdst=1 gmtoff=-25200
/usr/share/zoneinfo/America/Los_Angeles Sun Oct 25 08:59:59 1970 UT = Sun Oct 25 01:59:59 1970 PDT isdst=1 gmtoff=-25200
/usr/share/zoneinfo/America/Los_Angeles Sun Oct 25 09:00:00 1970 UT = Sun Oct 25 01:00:00 1970 PST isdst=0 gmtoff=-28800
/usr/share/zoneinfo/America/Dawson_Creek Sun Apr 26 09:59:59 1970 UT = Sun Apr 26 01:59:59 1970 PST isdst=0 gmtoff=-28800
/usr/share/zoneinfo/America/Dawson_Creek Sun Apr 26 10:00:00 1970 UT = Sun Apr 26 03:00:00 1970 PDT isdst=1 gmtoff=-25200
/usr/share/zoneinfo/America/Dawson_Creek Sun Oct 25 08:59:59 1970 UT = Sun Oct 25 01:59:59 1970 PDT isdst=1 gmtoff=-25200
/usr/share/zoneinfo/America/Dawson_Creek Sun Oct 25 09:00:00 1970 UT = Sun Oct 25 01:00:00 1970 PST isdst=0 gmtoff=-28800

Related

how to take only times from dates inside array in rails

so... i need to take times from dates inside Array
so for example I have an array like this
a = [
Thu, 17 Mar 2022 10:00:00.000000000 KST +09:00,
Thu, 17 Mar 2022 10:00:00.000000000 KST +09:00,
Thu, 17 Mar 2022 14:00:00.000000000 KST +09:00,
Thu, 17 Mar 2022 14:00:00.000000000 KST +09:00,
Thu, 17 Mar 2022 17:00:00.000000000 KST +09:00]
and wanted to have result of
a = ["10:00", "10:00", "14:00", "14:00", "17:00"]
So i was trying this
can_choose =[];
a.each_with_index do |time| strftime("%H:%M")
can_choose <<|time|
but doesn't works at all...
where should I have to fix??
You can also extract the year, month, day the same way
https://ruby-doc.org/stdlib-3.1.1/libdoc/date/rdoc/Date.html
a = [
'Thu, 17 Mar 2022 10:00:00.000000000 KST +09:00',
'Thu, 17 Mar 2022 10:00:00.000000000 KST +09:00',
'Thu, 17 Mar 2022 14:00:00.000000000 KST +09:00',
'Thu, 17 Mar 2022 14:00:00.000000000 KST +09:00',
'Thu, 17 Mar 2022 17:00:00.000000000 KST +09:00']
can_choose =[]
a.map do |time|
t = DateTime.parse(time)
can_choose << t.strftime("%k:%M")
end
p can_choose
=> ["10:00", "10:00", "14:00", "14:00", "17:00"]
Ruby is all about message passing. The syntax to send a message is:
receiver.message(argument)
strftime is such message, but it needs a proper receiver. So if you have some Time instance, e.g.:
time = Time.parse('2022-03-17 10:00:00 +0900')
you'd write:
time.strftime('%H:%M') #=> "10:00"
with time being the receiver, strftime being the message and '%H:%M' being the argument.
You can use the above code in an each loop like this:
can_choose = []
a.each do |time|
can_choose << time.strftime('%H:%M')
end
Or you could use map to convert your array to another array:
can_choose = a.map { |time| time.strftime('%H:%M') }
The curly braces here { ... } are equivalent to the do ... end block above.
I would simple go with:
can_choose = a.map { |datetime| datetime.strftime('%H:%M') }
If you need only hours and minutes in 24h format, just use %R directive with Time#strftime or DateTime#strftime
can_choose = a.map { |time| time.strftime('%R') }

mktime or tz database unexpected return for 1941

mktime returns for july 3rd 1941 (00:00:00) and july 4th 1941 (00:00:00) are unexpected.
The difference between the two is 82800 seconds, lacking a full hour (3600).
The C program diff1941.c (see below) shows the following :
$> diff1941
july3=-899337600i
diff:82800 should be 86400
At first I thought it was a TZ Database hour shift, but as far as I understand, and according to zdump command, there is no such shift for 1941.
zdump -v -c 1940,1943 /etc/localtime
/etc/localtime Sun Feb 25 01:59:59 1940 UT = Sun Feb 25 01:59:59 1940 WET isdst=0 gmtoff=0
/etc/localtime Sun Feb 25 02:00:00 1940 UT = Sun Feb 25 03:00:00 1940 WEST isdst=1 gmtoff=3600
/etc/localtime Fri Jun 14 21:59:59 1940 UT = Fri Jun 14 22:59:59 1940 WEST isdst=1 gmtoff=3600
/etc/localtime Fri Jun 14 22:00:00 1940 UT = Sat Jun 15 00:00:00 1940 CEST isdst=1 gmtoff=7200
/etc/localtime Mon Nov 2 00:59:59 1942 UT = Mon Nov 2 02:59:59 1942 CEST isdst=1 gmtoff=7200
/etc/localtime Mon Nov 2 01:00:00 1942 UT = Mon Nov 2 02:00:00 1942 CET isdst=0 gmtoff=3600
So at this point I am confused. Either my program has a bug that I can not see (possible), or there is a bug in lib C mktime function(unlikely), or there is something subtle in the TZ database and I can not find it (probable): what do you think of it ?
I am using:
Ubuntu 20.04 64 bits,
libc 2.31-0ubuntu9,
tzdata 2019c-3ubuntu1
/etc/localtime points on /usr/share/zoneinfo/Europe/Paris
diff1941.c:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
long int stamp(int d,int m,int y)
{
struct tm date;
memset(&date,0,sizeof(date));
date.tm_mday=d;
date.tm_mon=m-1;
date.tm_year=y-1900;
return mktime(&date);
}
int main(int argc, char **argv)
{
if (argc>1)
setenv("TZ","0",1);
long int july3=stamp(3,7,1941);
long int july4=stamp(4,7,1941);
printf("july3=%ldi\n",july3);
printf("diff:%ld should be 86400\n",july4-july3);
}
Usually, when you see 1 hour difference in time, that means you should take a look at daylight saving time settings.
On both dates 3rd July 1941 and 4th July 1941 daylight saving time was in effect in France. You specify tm_isdst = 0, that means the daylight saving time is not in effect for your dates. So your dates are invalid - there was no such time as 3rd July 1941 with 00:00:00 with no DST.
Glibc mktime tries it's best to determine what time do you have in mind. Actually it determines the first of the dates as 3rd July 1941 02:00:00 and the second of the dates as 4th July 1941 01:00:00. The difference is one day minus one hour.
Either set isdst=-1 to let mktime "automagically" determine the current DST for your input times. In France it was DST all the time in 1941, it will determine isdst=1. Or explicit specify that you want DST by setting date.isdst=1.

Using Linux mktime to get timezone

I use the following codes to caculate timezone. When I set the timezone to Asia/Singapore, I think I should get 28800 which 28800/3600=8, it should be GMT +8, but it returns 27000/3600=7.5, Am I wrong?
struct tm tSysTime;
long int secs;
memset(&tSysTime,0,sizeof(tSysTime));
tSysTime.tm_year = 70;
tSysTime.tm_mon = 0;
tSysTime.tm_mday = 1;
tSysTime.tm_hour = 0;
tSysTime.tm_min = 0;
tSysTime.tm_sec = 0;
secs = 0-mktime(&tSysTime);
printf("[main] time zone %ld\n",secs);
Diagnosis
According to zdump -v Asia/Singapore on a Mac, the time zone offset from UTC for Singapore between August 1965 and January 1982 was 7h 30m east of UTC:
$ zdump -v Asia/Singapore
Asia/Singapore Fri Dec 13 20:45:52 1901 UTC = Sat Dec 14 03:41:17 1901 SMT isdst=0
Asia/Singapore Sat Dec 14 20:45:52 1901 UTC = Sun Dec 15 03:41:17 1901 SMT isdst=0
Asia/Singapore Wed May 31 17:04:34 1905 UTC = Wed May 31 23:59:59 1905 SMT isdst=0
Asia/Singapore Wed May 31 17:04:35 1905 UTC = Thu Jun 1 00:04:35 1905 MALT isdst=0
Asia/Singapore Sat Dec 31 16:59:59 1932 UTC = Sat Dec 31 23:59:59 1932 MALT isdst=0
Asia/Singapore Sat Dec 31 17:00:00 1932 UTC = Sun Jan 1 00:20:00 1933 MALST isdst=1
Asia/Singapore Tue Dec 31 16:39:59 1935 UTC = Tue Dec 31 23:59:59 1935 MALST isdst=1
Asia/Singapore Tue Dec 31 16:40:00 1935 UTC = Wed Jan 1 00:00:00 1936 MALT isdst=0
Asia/Singapore Sun Aug 31 16:39:59 1941 UTC = Sun Aug 31 23:59:59 1941 MALT isdst=0
Asia/Singapore Sun Aug 31 16:40:00 1941 UTC = Mon Sep 1 00:10:00 1941 MALT isdst=0
Asia/Singapore Sun Feb 15 16:29:59 1942 UTC = Sun Feb 15 23:59:59 1942 MALT isdst=0
Asia/Singapore Sun Feb 15 16:30:00 1942 UTC = Mon Feb 16 01:30:00 1942 JST isdst=0
Asia/Singapore Tue Sep 11 14:59:59 1945 UTC = Tue Sep 11 23:59:59 1945 JST isdst=0
Asia/Singapore Tue Sep 11 15:00:00 1945 UTC = Tue Sep 11 22:30:00 1945 MALT isdst=0
Asia/Singapore Sun Aug 8 16:29:59 1965 UTC = Sun Aug 8 23:59:59 1965 MALT isdst=0
Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0
Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0
Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0
Asia/Singapore Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 11:14:07 2038 SGT isdst=0
Asia/Singapore Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 11:14:07 2038 SGT isdst=0
$
Consequently, the result you're getting is the correct offset from UTC in Singapore for 1970-01-01.
Subsidiary question
The current timezone of Singapore is GMT8. What I should do to fix this problem?
The current time zone offset of Singapore is UTC+8 (GMT+8), but historically (specifically, in 1970), that was not the case. You will have to devise a time nearer to the current time when the time zone offset in the database is correct. That seems to mean a time since 1982-01-01 00:30:00 +08:00. So, maybe you should use 2000-01-01 00:00:00? You'll need the number of seconds in the 30 years since 1970-01-01 00:00:00 to get the answer right, and you'll use that in place of the 0 in 0 - mktime(&tSysTime). I believe the relevant number is 946684800.
Revised C code
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void)
{
struct tm tSysTime;
long int secs;
memset(&tSysTime,0,sizeof(tSysTime));
tSysTime.tm_year = 100;
tSysTime.tm_mon = 0;
tSysTime.tm_mday = 1;
tSysTime.tm_hour = 0;
tSysTime.tm_min = 0;
tSysTime.tm_sec = 0;
secs = 946684800 - mktime(&tSysTime);
printf("[main] time zone %ld\n",secs);
return 0;
}
Example runs
$ TZ=Asia/Singapore tzoff
[main] time zone 28800
$ TZ=US/Pacific tzoff
[main] time zone -28800
$ TZ=UTC0 tzoff
[main] time zone 0
$
How did you find 946684800
That's a deep-seated mystery. No, it isn't. I have a pair of programs, strptime and timestamp that helped (plus a casual use of bc).
I live in the 'US/Pacific' (officially, America/Los_Angeles, but I don't like that name much — I live a lot closer to San Francisco) time zone (UTC-08:00 in the winter; UTC-07:00 during the summer).
$ strptime '2000-01-01 00:00:00'
946713600 = 2000-01-01 00:00:00
$ timestamp 946713600
946713600 = Sat Jan 01 00:00:00 2000
$ timestamp -Z 946713600
946713600 = Sat Jan 01 00:00:00 2000 -08:00
$ bc <<< '946713600 - 8 * 3600'
946684800
$ timestamp -Z 946684800
946684800 = Fri Dec 31 16:00:00 1999 -08:00
$ TZ=UTC0 timestamp -Z 946684800
946684800 = Sat Jan 01 00:00:00 2000 +00:00
$
If you spend the time working out how, you can probably do that with GNU date.

Find the most recent date from an Array

How to find the most recent date from an array like the one below?
Tue Jun 2 17:59:54 GMT+0200 2013
Tue Jun 5 18:00:10 GMT+0200 2013
Tue Jun 1 12:27:14 GMT+0200 2013
Tue Jun 3 17:26:58 GMT+0200 2013
Tue Jun 9 17:27:49 GMT+0200 2013
Tue Jun 1 13:27:39 GMT+0200 2015
Tue Jun 3 12:27:59 GMT+0200 2013
Tue Jun 6 15:27:22 GMT+0200 2014
Tue Jun 2 17:27:30 GMT+0200 2014
Assuming your array is full of AS3 native Date objects, you could simply do this:
array.sortOn("time",Array.DESCENDING);
trace("Most Recent:",array[0]);
You cannot use array.sort (unless you use the Array.NUMERIC flag) because it will sort the string representation of the date. So all your days of the week would then be grouped together instead of the actual date.
If your dates are strings, then you will need to convert them to Date objects prior to sorting:
//assuming your posted array is in a var called 'stringArray'
var dateArray:Array = []; //a new array to hold the converted strings
for(var i:int=0;i<stringArray.length;i++){
dateArray.push(new Date(stringArray[i]));
}
dateArray.sortOn("time",Array.DESCENDING);
trace("Most Recent Date:",dateArray[0]);
To show this in a concrete example, here is your posted dates - copy paste this code to produce the same results:
var arr:Array = new Array(
new Date("Tue Jun 2 17:59:54 GMT+0200 2013"),
new Date("Tue Jun 5 18:00:10 GMT+0200 2013"),
new Date("Tue Jun 1 12:27:14 GMT+0200 2013"),
new Date("Tue Jun 3 17:26:58 GMT+0200 2013"),
new Date("Tue Jun 9 17:27:49 GMT+0200 2013"),
new Date("Tue Jun 1 13:27:39 GMT+0200 2015"),
new Date("Tue Jun 3 12:27:59 GMT+0200 2013"),
new Date("Tue Jun 6 15:27:22 GMT+0200 2014"),
new Date("Tue Jun 2 17:27:30 GMT+0200 2014")
);
arr.sort(Array.DESCENDING);
trace("SORT:");
traceDates();
arr.sortOn("time",Array.DESCENDING);
trace("\nSORT ON:");
traceDates();
function traceDates(){
for(var i:int=0;i<arr.length;i++){
trace(" ",arr[i].fullYear + "-" + arr[i].month + "-" + arr[i].day);
}
}
//OUTPUT:
/*
SORT:
2013-5-3
2013-5-0
2013-5-0
2013-5-6
2013-5-1
2013-5-1
2014-5-1
2015-5-1 //most recent date, second to LAST item in the array
2014-5-5
SORT ON:
2015-5-1 //June 1st is the most recent date (first item in the array)
2014-5-5
2014-5-1
2013-5-0
2013-5-3
2013-5-1
2013-5-1
2013-5-0
2013-5-6
*/
Are they Date objects?
If so, you can compare the time property of each. It will give you the number of milliseconds since Jan 1, 1970. The highest number will be the most recent.
Something along these lines:
var mostRecentDate:Date = dateArray[0];
for(var i:int = 0; i < dateArray.length; i++){
if(dateArray[i].time > mostRecentDate.time){
mostRecentDate = dateArray[i];
}
}
Date objects act like simple Number when it comes to sorting or comparison. All you have to do is treat them like Numbers. So taken from Cadin answer:
dateArray.sort();
var oldestDate:Date = dateArray[0];
Will get you the oldest Date while:
dateArray.sort(Array.DESCENDING);
var mostRecentDate:Date = dateArray[0];
Will get you the most recent one.
For LDMS, this is what I got:
var firstdate:Date = new Date();
var seconddate:Date = new Date();
var thirddate:Date = new Date();
seconddate.time = firstdate.time + 5000000;
thirddate.time = firstdate.time + 50000000;
trace(seconddate > firstdate)//true
trace(firstdate > seconddate)//false
trace(seconddate.time > firstdate.time)//true
var array:Array = [thirddate, firstdate, seconddate];
trace(array)
//Wed Jun 3 03:37:40 GMT-0400 2015,Tue Jun 2 13:44:20 GMT-0400 2015,Tue Jun 2 15:07:40 GMT-0400 2015
array.sort();
trace(array)
//Tue Jun 2 13:44:20 GMT-0400 2015,Tue Jun 2 15:07:40 GMT-0400 2015,Wed Jun 3 03:37:40 GMT-0400 2015
array.sort(Array.DESCENDING);
trace(array)
//Wed Jun 3 03:37:40 GMT-0400 2015,Tue Jun 2 15:07:40 GMT-0400 2015,Tue Jun 2 13:44:20 GMT-0400 2015
Sort the array and grab the first (descending) or last (ascending) element.
Edit: 2 down-votes because I didn't provide an example, or because people don't know you can sort dates? This works:
var dates:Array = [
"Tue Jun 2 17:59:54 GMT+0200 2013",
"Tue Jun 5 18:00:10 GMT+0200 2013",
"Tue Jun 1 12:27:14 GMT+0200 2013",
"Tue Jun 3 17:26:58 GMT+0200 2013",
"Tue Jun 9 17:27:49 GMT+0200 2013",
"Tue Jun 1 13:27:39 GMT+0200 2015",
"Tue Jun 3 12:27:59 GMT+0200 2013",
"Tue Jun 6 15:27:22 GMT+0200 2014",
"Tue Jun 2 17:27:30 GMT+0200 2014"
].map(function(s:String, i:int, a:Array):Date {
return new Date(s);
}).sort(Array.NUMERIC | Array.DESCENDING);
var latest:Date = dates[0]; // Mon Jun 1 07:27:39 GMT-0400 2015
The problem is the OP did not make it clear what kind of data they are working with (strings or Date objects) so the exact solution code is unknown.

Using Arrays in Rabl

I am returning a collection from the query. The query is in this thread.
So my result is like below in my log:
[{"id"=>1, "name"=>"ASP.NET-WebForms", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:04:18 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:04:18 UTC +00:00, "skill_type"=>"Serverside-Framework", :assigned=>true}, {"id"=>2, "name"=>"ASP.NET-MVC", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:05:01 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:05:01 UTC +00:00, "skill_type"=>"Serverside-Framework", :assigned=>true}, {"id"=>3, "name"=>"RUBY-ON-RAILS", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:05:20 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:05:20 UTC +00:00, "skill_type"=>"Serverside-Framework", :assigned=>false}, {"id"=>4, "name"=>"C#", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>2, "created_at"=>Thu, 23 Apr 2015 06:05:57 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:12:02 UTC +00:00, "skill_type"=>"Language", :assigned=>false}, {"id"=>5, "name"=>"Ruby", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:07:43 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:07:43 UTC +00:00, "skill_type"=>"Language", :assigned=>true}, {"id"=>6, "name"=>"VB", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:08:15 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:08:15 UTC +00:00, "skill_type"=>"Language", :assigned=>false}, {"id"=>7, "name"=>"SQL-Server", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:08:32 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:08:32 UTC +00:00, "skill_type"=>"DBMS", :assigned=>false}, {"id"=>8, "name"=>"MySQL", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:08:49 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:08:49 UTC +00:00, "skill_type"=>"DBMS", :assigned=>false}, {"id"=>9, "name"=>"Oracle", "description"=>"", "record_status"=>1, "created_by"=>1, "updated_by"=>1, "created_at"=>Thu, 23 Apr 2015 06:09:01 UTC +00:00, "updated_at"=>Thu, 23 Apr 2015 06:09:01 UTC +00:00, "skill_type"=>"DBMS", :assigned=>false}]
I think this is an array instead of an object collection. So how can I display this as json using rabl. The collection #technical_skills is not working.
My expected output is:
{
"domain_skill": {
"id": 1,
"name": "domain name",
"description": "some description text",
"technical_skills": [
{
"id": 1,
"name": "ASP.NET-WebForms",
"assigned": true
},
{
"id": 2,
"name": "ASP.NET-MVC",
"assigned": true
}
]
}
}
Edit:
I got that this is a json array. My method to merge another field so that I can convert this to json and merge the new fields. Now I thought this is json array. Please check my controller method below:
id = params[:id]
#domain_skill_technical_skill_ids = DomainSkillsTechnicalSkill.select('id, technical_skill_id').where(domain_skill_id: id).collect(&:technical_skill_id)
Rails.logger.info(#domain_skill_technical_skill_ids.to_a)
#technical_skills = []
TechnicalSkill.select('id, name').where(record_status: 1).each do |skill|
#technical_skills << skill.as_json.merge!(
{ assigned: #domain_skill_technical_skill_ids.include?(skill.id)}
)
end
#domain_skill_view_model = DomainSkillViewModel.new(#domain_skill, #technical_skills)
respond_with #domain_skill_view_model
My rabl:
object :#domain_skill_view_model
object :#domain_skill
attributes :id, :name, :description
node :technical_skills do
#technical_skills.each do |skill|
end
end

Resources