Hello,

On Thu Oct 21, 2021 at 8:04 PM CEST, Hans Hagen via ntg-context wrote:
> I cleaned up some more backend code. There were some mails about dates
> and such and although the date field in setupinteraction works ok a more
> drastic overload is doen with directives. The reason is that the fact
> that we can set the date (and traler) is only because it permits
> generating pdf files that can be compared. No date as a bad idea anyway.
>
> \setupinteraction[title=My Title]
> % \enabledirectives[backend.date=2034-06-07]
> \enabledirectives[backend.date=no]
> \enabledirectives[backend.trailerid=no]

I checked the backend code and some of the related os functions. I put
together a patch that hopefully fixes some stuff and doesn't break
anything. The changes:

1) Dates parsed by ConTeXt (function converters.totime), such as those
that are input to backend.date, now allow specifying seconds and time
zone information. If there is no timezone the datetime is presumed to be
in local time, otherwise the datetime is offset by the local / specified
time zone difference (because ConTeXt outputs these dates as local times
with local timezone). Additionally both "T" and " " are now allowed as
date/time separator characters. Thus dates output by ConTeXt can be also
fed in.

2) Fix the os.timezone function. Previously, it could be wrong around
midnight, which I discovered only by chance. The trick is lifted from
http://lua-users.org/wiki/TimeZone, which I hope is OK. The before and
after (I am at +02:00):

    os.localtime()  2021-10-22 01:44:24
    os.now()        2021-10-21 23:44:24
    os.timezone(true)       -22:00


    os.localtime()  2021-10-22 01:46:23
    os.now()        2021-10-21 23:46:23
    os.timezone(true)       +02:00

I also extended the interface of os.timezone to accommodate 1), but as
this is probably a very public interface, I am not sure if these changes
are OK. If more changes to the interface can be made, I propose to get
rid of the delta parameter, since it seems like a remnant from the past.

Some caching can also be introduced, but I again wasn't sure if this
even would be the final form of the function, so didn't do anything in
that sense, yet.

3) Don't use %X in time formats. It is specified to be platform
dependent and we want %H:%M:%S everywhere. Also, it would be nice if
lpdf-xmp.lmt would use the os.fulltime() function to format dates (like
back-exp.lmt does), but there are multiple dates with different formats
and purposes and it is probably too late to change now.

4) I changed the os.fulltime function, that returns date + time + local
time zone to output the _local_ time instead of UTC time. This is AFAICT
the right way to do times. The PDF spec says:

    If no UT information is specified, the relationship of the specified
    time to UT shall be considered to be GMT. Regardless of whether the
    time zone is specified, the rest of the date shall be specified in
    local time.

    EXAMPLE: For example, December 23, 1998, at 7:52 PM, U.S. Pacific
    Standard Time, is represented by the string D:199812231952-08'00

A test program:


    \enabletrackers[backend.info]
    
    \enabledirectives[backend.date=1234-12-30]                % 
1234-12-30T00:00:00+02:00
    \enabledirectives[backend.date=1234-12-30 23:45]          % 
1234-12-30T23:45:00+02:00
    \enabledirectives[backend.date=1234-12-30 23:45:16]       % 
1234-12-30T23:45:16+02:00
    \enabledirectives[backend.date=1234-12-30T23:45:16+01:00] % 
1234-12-31T00:45:16+02:00
    \enabledirectives[backend.date=1234-12-30 23:45:16-02:00] % 
1234-12-31T03:45:16+02:00
    \enabledirectives[backend.date=1234-12-30 23:45:16+05:00] % 
1234-12-31T20:45:16+02:00
    
    \starttext
    dummy text
    
    \startluacode
    print("os.timezone(true)", os.timezone(true)) -- +02:00
    print("os.fulltime()", os.fulltime())         -- 2021-10-22 17:38:38+02:00
    print("os.localtime()", os.localtime())       -- 2021-10-22 17:38:38
    print("os.now()", os.now())                   -- 2021-10-22 15:38:38
    \stopluacode
    \stoptext

I don't claim to know LPEG so please check my work. I also know nothing
about XMP, so I didn't check that at all, sorry.

Is the timezone stuff what you wanted Pablo?

Full patch temporarily at this URL and also below:

https://github.com/contextgarden/context-mirror/compare/beta...vlasakm:dates

Michal

--- a/tex/context/base/mkiv/core-con.lua
+++ b/tex/context/base/mkiv/core-con.lua
@@ -17,7 +17,7 @@ slower but look nicer this way.</p>
 --ldx]]--
 
 local floor = math.floor
-local osdate, ostime = os.date, os.time
+local osdate, ostime, ostimezone = os.date, os.time, os.timezone
 local concat, insert, reverse = table.concat, table.insert, table.reverse
 local lower, upper, rep, match, gsub = string.lower, string.upper, string.rep, 
string.match, string.gsub
 local utfchar, utfbyte = utf.char, utf.byte
@@ -1972,13 +1972,18 @@ implement {
 }
 
 local n = R("09")^1 / tonumber
+local sign = S("+-") / function(s) return tonumber(s.."1") end
 
 local p = Cf( Ct("")
     * Cg(Cc("year")  * (n           )) * P("-")^-1
     * Cg(Cc("month") * (n + Cc(   1))) * P("-")^-1
-    * Cg(Cc("day")   * (n + Cc(   1))) * whitespace^-1
+    * Cg(Cc("day")   * (n + Cc(   1))) * (whitespace + P("T"))^-1
     * Cg(Cc("hour")  * (n + Cc(   0))) * P(":")^-1
-    * Cg(Cc("min")   * (n + Cc(   0)))
+    * Cg(Cc("min")   * (n + Cc(   0))) * P(":")^-1
+    * Cg(Cc("sec")   * (n + Cc(   0)))^-1
+    *(Cg(Cc("tzsgn") * sign)
+    * Cg(Cc("tzh")   * (n + Cc(   0))) * P(":")^-1
+    * Cg(Cc("tzm")   * (n + Cc(   0))))^-1
     , rawset)
 
 function converters.totime(s)
@@ -1987,7 +1992,13 @@ function converters.totime(s)
     elseif type(s) == "table" then
         return s
     elseif type(s) == "string" then
-        return lpegmatch(p,s)
+        local t = lpegmatch(p,s)
+        if t.tzh then
+            local localtzh, localtzm = ostimezone(true, true)
+            t.hour = t.hour + localtzh - t.tzsgn * t.tzh
+            t.min  = t.min  + localtzm - t.tzsgn * t.tzm or 0
+        end
+        return t
     end
     local n = tonumber(s)
     if n and n >= 0 then
--- a/tex/context/base/mkiv/l-os.lua
+++ b/tex/context/base/mkiv/l-os.lua
@@ -26,10 +26,10 @@ if not modules then modules = { } end modules ['l-os'] = {
 -- 
math.randomseed(tonumber(string.sub(string.reverse(tostring(math.floor(socket.gettime()*10000))),1,6)))
 
 local os = os
-local date, time = os.date, os.time
+local date, time, difftime = os.date, os.time, os.difftime
 local find, format, gsub, upper, gmatch = string.find, string.format, 
string.gsub, string.upper, string.gmatch
 local concat = table.concat
-local random, ceil, randomseed = math.random, math.ceil, math.randomseed
+local random, ceil, randomseed, modf = math.random, math.ceil, 
math.randomseed, math.modf
 local type, setmetatable, tonumber, tostring = type, setmetatable, tonumber, 
tostring
 
 -- This check needs to happen real early on. Todo: we can pick it up from the 
commandline
@@ -434,15 +434,22 @@ end
 
 do
 
-    local d
-
-    function os.timezone(delta)
-        d = d or ((tonumber(date("%H")) or 0) - (tonumber(date("!%H")) or 0))
+    -- http://lua-users.org/wiki/TimeZone
+    -- +02:00
+    function os.timezone(delta, diff)
         if delta then
-            if d > 0 then
-                return format("+%02i:00",d)
+            local t         = time()
+            local utcdate   = os.date("!*t", t)
+            local localdate = os.date("*t", t)
+            localdate.isdst  = false
+            local timediff  = os.difftime(time(localdate), time(utcdate))
+            local hour, min = math.modf(timediff / 3600)
+            min = min * 60
+
+            if diff then
+                return hour, min
             else
-                return format("-%02i:00",-d)
+                return format("%+03d:%02d", hour, min)
             end
         else
             return 1
@@ -450,10 +457,12 @@ do
     end
 
     local timeformat = format("%%s%s",os.timezone(true))
-    local dateformat = "!%Y-%m-%d %H:%M:%S"
+    local dateformat = "%Y-%m-%d %H:%M:%S"
     local lasttime   = nil
     local lastdate   = nil
 
+    -- localtime + timezone
+    -- 2021-10-22 10:22:54+02:00
     function os.fulltime(t,default)
         t = t and tonumber(t) or 0
         if t > 0 then
@@ -474,6 +483,8 @@ do
     local lasttime   = nil
     local lastdate   = nil
 
+    -- localtime without timezone
+    -- 2021-10-22 10:22:54
     function os.localtime(t,default)
         t = t and tonumber(t) or 0
         if t > 0 then
@@ -503,8 +514,10 @@ do
         return date("!*t") -- table with values
     end
 
+    -- utc time without timezone
+    -- 2021-10-22 08:22:54
     function os.now()
-        return date("!%Y-%m-%d %H:%M:%S") -- 2011-12-04 14:59:12
+        return date("!%Y-%m-%d %H:%M:%S")
     end
 
 end
--- a/tex/context/base/mkxl/lpdf-xmp.lmt
+++ b/tex/context/base/mkxl/lpdf-xmp.lmt
@@ -151,7 +151,7 @@ local function pdfsetmetadate(n,both)
     if n then
         n = converters.totime(n)
         if n then
-            creationdate = osdate("%Y-%m-%dT%X",ostime(n)) .. ostimezone(true)
+            creationdate = osdate("%Y-%m-%dT%H:%M:%S",ostime(n)) .. 
ostimezone(true)
             if both then
                 modificationdate = creationdate
             end
@@ -190,7 +190,7 @@ local function setdates(v)
         end
     end
     if toboolean(v) then
-        creationdate     = osdate("%Y-%m-%dT%X") .. ostimezone(true)
+        creationdate     = osdate("%Y-%m-%dT%H:%M:%S") .. ostimezone(true)
         modificationdate = creationdate
     else
         creationdate     = false
-- 
2.33.1

___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the 
Wiki!

maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : http://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : http://contextgarden.net
___________________________________________________________________________________

Reply via email to