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