"Fossies" - the Fresh Open Source Software Archive

Member "nmap-7.91/nselib/datetime.lua" (10 Oct 2020, 8257 Bytes) of package /linux/misc/nmap-7.91.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Lua source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "datetime.lua": 7.90_vs_7.91.

    1 --- Functions for dealing with dates and timestamps
    2 --
    3 -- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
    4 -- @class module
    5 -- @name datetime
    6 -- @author Daniel Miller
    7 
    8 local stdnse = require "stdnse"
    9 local os = require "os"
   10 local math = require "math"
   11 local string = require "string"
   12 _ENV = stdnse.module("datetime", stdnse.seeall)
   13 
   14 local difftime = os.difftime
   15 local time = os.time
   16 local date = os.date
   17 
   18 local floor = math.floor
   19 local fmod = math.fmod
   20 
   21 local format = string.format
   22 local match = string.match
   23 
   24 --- Record a time difference between the scanner and the target
   25 --
   26 -- The skew will be recorded in the host's registry for later retrieval and
   27 -- analysis. Adjusts for network distance by subtracting half the smoothed
   28 -- round-trip time.
   29 --
   30 --@param host The host being scanned
   31 --@param timestamp The target timestamp, in seconds.
   32 --@param received The local time the stamp was received, in seconds.
   33 function record_skew(host, timestamp, received)
   34   local skew_tab = host.registry.datetime_skew
   35   skew_tab = skew_tab or {}
   36   -- No srtt? I suppose we'll ignore it, but this could cause problems
   37   local srtt = host.times and host.times.srtt or 0
   38   local adjusted = difftime(floor(timestamp), floor(received)) - srtt / 2.0
   39   skew_tab[#skew_tab + 1] = adjusted
   40   stdnse.debug2("record_skew: %s", adjusted)
   41   host.registry.datetime_skew = skew_tab
   42 end
   43 
   44 -- Work around Windows error formatting time zones where 1970/1/1 UTC was 1969/12/31
   45 local utc_offset_seconds
   46 do
   47   -- What does the calendar say locally?
   48   local localtime = date("*t", 86400)
   49   -- What does the calendar say in UTC?
   50   local gmtime = date("!*t", 86400)
   51   -- Interpret both as local calendar dates and find the difference.
   52   utc_offset_seconds = difftime(time(localtime), time(gmtime))
   53 end
   54 
   55 -- The offset in seconds between local time and UTC.
   56 --
   57 -- That is, if we interpret a UTC date table as a local date table by passing
   58 -- it to os.time, how much must be added to the resulting integer timestamp to
   59 -- make it correct?
   60 --
   61 -- In other words, subtract this value from a timestamp if you intend to use it
   62 -- in os.date.
   63 function utc_offset() return utc_offset_seconds end
   64 
   65 --- Convert a date table into an integer timestamp.
   66 --
   67 -- Unlike os.time, this does not assume that the date table represents a local
   68 -- time. Rather, it takes an optional offset number of seconds representing the
   69 -- time zone, and returns the timestamp that would result using that time zone
   70 -- as local time. If the offset is omitted or 0, the date table is interpreted
   71 -- as a UTC date. For example, 4:00 UTC is the same as 5:00 UTC+1:
   72 -- <code>
   73 -- date_to_timestamp({year=1970,month=1,day=1,hour=4,min=0,sec=0})          --> 14400
   74 -- date_to_timestamp({year=1970,month=1,day=1,hour=4,min=0,sec=0}, 0)       --> 14400
   75 -- date_to_timestamp({year=1970,month=1,day=1,hour=5,min=0,sec=0}, 1*60*60) --> 14400
   76 -- </code>
   77 -- And 4:00 UTC+1 is an earlier time:
   78 -- <code>
   79 -- date_to_timestamp({year=1970,month=1,day=1,hour=4,min=0,sec=0}, 1*60*60) --> 10800
   80 -- </code>
   81 function date_to_timestamp(date_t, offset)
   82   local status, tm = pcall(time, date_t)
   83   if not status then
   84     stdnse.debug1("Invalid date for this platform: %s", tm)
   85     return nil
   86   end
   87   offset = offset or 0
   88   return tm + utc_offset() - offset
   89 end
   90 
   91 local function format_tz(offset)
   92   local sign, hh, mm
   93 
   94   if not offset then
   95     return ""
   96   end
   97   if offset < 0 then
   98     sign = "-"
   99     offset = -offset
  100   else
  101     sign = "+"
  102   end
  103   -- Truncate to minutes.
  104   offset = floor(offset / 60)
  105   hh = floor(offset / 60)
  106   mm = floor(fmod(offset, 60))
  107 
  108   return format("%s%02d:%02d", sign, hh, mm)
  109 end
  110 --- Format a date and time (and optional time zone) for structured output.
  111 --
  112 -- Formatting is done according to RFC 3339 (a profile of ISO 8601), except
  113 -- that a time zone may be omitted to signify an unspecified local time zone.
  114 -- Time zones are given as an integer number of seconds from UTC. Use
  115 -- <code>0</code> to mark UTC itself. Formatted strings with a time zone look
  116 -- like this:
  117 -- <code>
  118 -- format_timestamp(os.time(), 0)       --> "2012-09-07T23:37:42+00:00"
  119 -- format_timestamp(os.time(), 2*60*60) --> "2012-09-07T23:37:42+02:00"
  120 -- </code>
  121 -- Without a time zone they look like this:
  122 -- <code>
  123 -- format_timestamp(os.time())          --> "2012-09-07T23:37:42"
  124 -- </code>
  125 --
  126 -- This function should be used for all dates emitted as part of NSE structured
  127 -- output.
  128 function format_timestamp(t, offset)
  129   if type(t) == "table" then
  130     return format(
  131       "%d-%02d-%02dT%02d:%02d:%02d",
  132       t.year, t.month, t.day, t.hour, t.min, t.sec
  133       )
  134   else
  135     local tz_string = format_tz(offset)
  136     offset = offset or 0
  137     local status, result = pcall(date, "!%Y-%m-%dT%H:%M:%S", floor(t + offset))
  138     if not status then
  139       local tmp = floor(t + offset)
  140       local extra_years
  141       local seconds_in_year = 31556926
  142       if tmp > 0xffffffff then
  143         -- Maybe too far in the future?
  144         extra_years = (tmp  - 0xffffffff) // seconds_in_year + 1
  145       elseif tmp < -utc_offset() then
  146         -- Windows can't display times before the epoch
  147         extra_years = tmp // seconds_in_year
  148       end
  149       if extra_years then
  150         tmp = tmp - extra_years * seconds_in_year
  151         status, result = pcall(date, "!*t", tmp)
  152         if status then
  153           -- seconds_in_year is imprecise, so we truncate to date only
  154           result = format("%d-%02d-%02d?", result.year + extra_years, result.month, result.day)
  155         end
  156       end
  157     end
  158     if not status then
  159       return ("Invalid timestamp: %s"):format(t)
  160     end
  161     return result .. tz_string
  162   end
  163 end
  164 
  165 --- Format a time interval into a string
  166 --
  167 -- String is in the same format as format_difftime
  168 -- @param interval A time interval
  169 -- @param unit The time unit division as a number. If <code>interval</code> is
  170 --             in milliseconds, this is 1000 for instance. Default: 1 (seconds)
  171 -- @return The time interval in string format
  172 function format_time(interval, unit)
  173   local sign = ""
  174   if interval < 0 then
  175     sign = "-"
  176     interval = math.abs(interval)
  177   end
  178   unit = unit or 1
  179   local precision = floor(math.log(unit, 10))
  180 
  181   local sec = (interval % (60 * unit)) / unit
  182   interval = interval // (60 * unit)
  183   local min = interval % 60
  184   interval = interval // 60
  185   local hr = interval % 24
  186   interval = interval // 24
  187 
  188   local s = format("%.0fd%02.0fh%02.0fm%02.".. precision .."fs",
  189     interval, hr, min, sec)
  190   -- trim off leading 0 and "empty" units
  191   return sign .. (match(s, "([1-9].*)") or format("%0.".. precision .."fs", 0))
  192 end
  193 
  194 --- Format the difference between times <code>t2</code> and <code>t1</code>
  195 -- into a string
  196 --
  197 -- String is in one of the forms (signs may vary):
  198 -- * 0s
  199 -- * -4s
  200 -- * +2m38s
  201 -- * -9h12m34s
  202 -- * +5d17h05m06s
  203 -- * -2y177d10h13m20s
  204 -- The string shows <code>t2</code> relative to <code>t1</code>; i.e., the
  205 -- calculation is <code>t2</code> minus <code>t1</code>.
  206 function format_difftime(t2, t1)
  207   local d, s, sign, yeardiff
  208 
  209   d = difftime(time(t2), time(t1))
  210   if d > 0 then
  211     sign = "+"
  212   elseif d < 0 then
  213     sign = "-"
  214     t2, t1 = t1, t2
  215     d = -d
  216   else
  217     sign = ""
  218   end
  219   -- t2 is always later than or equal to t1 here.
  220 
  221   -- The year is a tricky case because it's not a fixed number of days
  222   -- the way a day is a fixed number of hours or an hour is a fixed
  223   -- number of minutes. For example, the difference between 2008-02-10
  224   -- and 2009-02-10 is 366 days because 2008 was a leap year, but it
  225   -- should be printed as 1y0d0h0m0s, not 1y1d0h0m0s. We advance t1 to be
  226   -- the latest year such that it is still before t2, which means that its
  227   -- year will be equal to or one less than t2's. The number of years
  228   -- skipped is stored in yeardiff.
  229   if t2.year > t1.year then
  230     local tmpyear = t1.year
  231     -- Put t1 in the same year as t2.
  232     t1.year = t2.year
  233     d = difftime(time(t2), time(t1))
  234     if d < 0 then
  235       -- Too far. Back off one year.
  236       t1.year = t2.year - 1
  237       d = difftime(time(t2), time(t1))
  238     end
  239     yeardiff = t1.year - tmpyear
  240     t1.year = tmpyear
  241   else
  242     yeardiff = 0
  243   end
  244 
  245   local s = format_time(d)
  246   if yeardiff == 0 then return sign .. s end
  247   -- Years.
  248   s = format("%dy", yeardiff) .. s
  249   return sign .. s
  250 end
  251 
  252 return _ENV