Convert string to date

So, just to give something back.
Here is code to calculate times going back every 15 minutes, rounded to nearest 15 minutes.
Still puzzled by @rob and the issue of %F etc.

[code]
local function makeDate(date)
if string.len(date)==1 then date=“0”…date end
return date
end

local date = os.date( “*t” )
date.min = date.min - 15;
t1=os.date("%Y%m%d%H", os.time(date))…makeDate(math.floor(os.date("%M", os.time(date))/15)*15)
date.min = date.min - 15;
t2=os.date("%Y%m%d%H", os.time(date))…makeDate(math.floor(os.date("%M", os.time(date))/15)*15)

[/code] [import]uid: 120570 topic_id: 34760 reply_id: 141174[/import]

print(os.date("%FT%X%z"))

According to the strftime man page, %F is the same as: %Y-%m-%d (the ISO 8601 date format).

http://linux.die.net/man/3/strftime

I’m guessing that Windows may have a different definition for strftime and maybe %F isn’t supported in Visual C++'s libraries. But you can sub the %Y-%m-%d in it’s place.
[import]uid: 199310 topic_id: 34760 reply_id: 141373[/import]

[quote=“rob,post:2,topic:309743”]

basically you have to parse the string into its component numbers, but its really not that hard. Here is a function I use for it:

function M.makeTimeStamp(dateString) local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)([%+%-])(%d+)%:(%d+)" local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = dateString:match(pattern) local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds}) local offset = xoffsethour \* 60 + xoffsetmin if xoffset == "-" then offset = offset \* -1 end return convertedTimestamp + offsetend

This looks much scarier than it really is. The goal is to turn that string into a Unix timestamp (number of seconds since Jan 1, 1970, the standard used by most systems). So we use the string.match() method to fetch the various date and time parts into their own variables: xyear, xmonth,etc.

Next we use the API call os.time() to convert all those individual parts into the timestamp. My code tries to adjust for time zones…

Now you have the time in a nice integer that you can easily manipulate and do date math. Now to determine how many days have passed since that date:

then = makeTimeStamp("2013-01-01T00:00:00Z")now = os.time()timeDifference = now - thendaysDifference = math.floor(timeDifference / (24 \* 60 \* 60)) -- 24 hours, 60 min, 60 seconds. I think it works out to 86400 seconds in a day or something like that...

[import]uid: 199310 topic_id: 34760 reply_id: 138198[/import] [/quote]

I get an error using this, it says “Field ‘day’ missing in date table”.

xday is indeed nil (in fact, all the other values too, it seems) from the match on this string: 2013-09-09T00:00:00Z, but… no, I don’t see where the fault lies either. :slight_smile:

Any ideas?

I made a simplified version, which works for strings like 2013-09-09:

function datetotime(s)     local xyear, xmonth, xday = s:match("(%d+)%-(%d+)%-(%d+)")     return os.time({year = xyear, month = xmonth, day = xday, hour = 0, min = 0, sec = 0}) end  

The function I use looks like this:

local makeTimeStamp = function(dateString) local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d\*)%:?(%d\*)"; local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = dateString:match(pattern); local timestamp = os.time({year=year, month=month, day=day, hour=hour, min=minute, sec=seconds}); local offset = 0; if (tzoffset) then if ((tzoffset == "+") or (tzoffset == "-")) then -- we have a timezone! offset = offsethour \* 60 + offsetmin; if (tzoffset == "-") then offset = offset \* -1; end timestamp = timestamp + offset; end end return timestamp; end

Sure, the pattern is different so that might have worked for me also.

Looks like the patterns are not flexible enough.  Try this:

function M.makeTimeStamp(dateString, mode)     local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d\*)%:?(%d\*)";     local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin     local monthLookup = {Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12}     local convertedTimestamp     local offset = 0     if mode and mode == "ctime" then         pattern = "%w+%s+(%w+)%s+(%d+)%s+(%d+)%:(%d+)%:(%d+)%s+(%w+)%s+(%d+)"         local monthName, TZName         monthName, xday, xhour, xminute, xseconds, TZName, xyear = string.match(dateString,pattern)         xmonth = monthLookup[monthName]         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})     else         xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = string.match(dateString,pattern)         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})         if xoffsetHour then             offset = xoffsethour \* 60 + xoffsetmin             if xoffset == "-" then                 offset = offset \* -1             end         end     end     return convertedTimestamp + offset end

@ conor:

math.floor(os.date("%M", os.time(date))/15)*15

always rounds downwards, not to nearest quarter hour

[quote=“rob,post:3,topic:309743”]

basically you have to parse the string into its component numbers, but its really not that hard. Here is a function I use for it:

function M.makeTimeStamp(dateString) local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)([%+%-])(%d+)%:(%d+)" local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = dateString:match(pattern) local convertedTimestamp = os.time({year = xyear, month = xmonth, day = xday, hour = xhour, min = xminute, sec = xseconds}) local offset = xoffsethour \* 60 + xoffsetmin if xoffset == "-" then offset = offset \* -1 end return convertedTimestamp + offsetend

This looks much scarier than it really is. The goal is to turn that string into a Unix timestamp (number of seconds since Jan 1, 1970, the standard used by most systems). So we use the string.match() method to fetch the various date and time parts into their own variables: xyear, xmonth,etc.

Next we use the API call os.time() to convert all those individual parts into the timestamp. My code tries to adjust for time zones…

Now you have the time in a nice integer that you can easily manipulate and do date math. Now to determine how many days have passed since that date:

then = makeTimeStamp("2013-01-01T00:00:00Z")now = os.time()timeDifference = now - thendaysDifference = math.floor(timeDifference / (24 \* 60 \* 60)) -- 24 hours, 60 min, 60 seconds. I think it works out to 86400 seconds in a day or something like that...

[import]uid: 199310 topic_id: 34760 reply_id: 138198[/import] [/quote]

I get an error using this, it says “Field ‘day’ missing in date table”.

xday is indeed nil (in fact, all the other values too, it seems) from the match on this string: 2013-09-09T00:00:00Z, but… no, I don’t see where the fault lies either. :slight_smile:

Any ideas?

I made a simplified version, which works for strings like 2013-09-09:

function datetotime(s)     local xyear, xmonth, xday = s:match("(%d+)%-(%d+)%-(%d+)")     return os.time({year = xyear, month = xmonth, day = xday, hour = 0, min = 0, sec = 0}) end  

The function I use looks like this:

local makeTimeStamp = function(dateString) local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d\*)%:?(%d\*)"; local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = dateString:match(pattern); local timestamp = os.time({year=year, month=month, day=day, hour=hour, min=minute, sec=seconds}); local offset = 0; if (tzoffset) then if ((tzoffset == "+") or (tzoffset == "-")) then -- we have a timezone! offset = offsethour \* 60 + offsetmin; if (tzoffset == "-") then offset = offset \* -1; end timestamp = timestamp + offset; end end return timestamp; end

Sure, the pattern is different so that might have worked for me also.

Looks like the patterns are not flexible enough.  Try this:

function M.makeTimeStamp(dateString, mode)     local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d\*)%:?(%d\*)";     local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin     local monthLookup = {Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12}     local convertedTimestamp     local offset = 0     if mode and mode == "ctime" then         pattern = "%w+%s+(%w+)%s+(%d+)%s+(%d+)%:(%d+)%:(%d+)%s+(%w+)%s+(%d+)"         local monthName, TZName         monthName, xday, xhour, xminute, xseconds, TZName, xyear = string.match(dateString,pattern)         xmonth = monthLookup[monthName]         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})     else         xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = string.match(dateString,pattern)         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})         if xoffsetHour then             offset = xoffsethour \* 60 + xoffsetmin             if xoffset == "-" then                 offset = offset \* -1             end         end     end     return convertedTimestamp + offset end

@ conor:

math.floor(os.date("%M", os.time(date))/15)*15

always rounds downwards, not to nearest quarter hour

I will say that I was unable to get this to work as part of your tutorial on IAP purchases, Rob.

I am horrible with regular expressions, but neither of the patterns that you have there match what I am getting back from the Google Play store today.

This is the string that I just got back as the transaction date:

Tue Jan 07 01:06:53 GMT+00:00 2014

Both of the patterns fail with all fields being nil.  And not sure why, because everything I have seen would indicate that this pattern would work for that string.

Try:

function M.makeTimeStamp(dateString, mode)     local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)([%+%-])(%d+)%:(%d+)"     local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin     local monthLookup = {Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12}     local convertedTimestamp     local offset = 0     if mode and mode == "ctime" then         pattern = "%w+ (%w+) (%d+) (%d+):(%d+):(%d+) (%w+) (%d+)"         local monthName, TZName         monthName, xday, xhour, xminute, xseconds, TZName, xyear = dateString:match(pattern)         xmonth = monthLookup[monthName]         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})     else         xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = dateString:match(pattern)         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})         offset = xoffsethour \* 60 + xoffsetmin         if xoffset == "-" then offset = offset \* -1 end     end     return convertedTimestamp + offset end

That above date works with dates that have Z timezone info, not +offset type dates.  This version should work (pulled it from code I use in my IAP based apps)…

Rob

Actually, Rob, that did not work for me either.  It appears that the GMT+00:00 is what is causing the issue.

From what I can see, I don’t think %w+ will capture all that.

I just changed the pattern to:

"%w+%s+(%w+)%s+(%d+)%s+(%d+)%:(%d+)%:(%d+)%s+(.+)%s+(%d+)"

(substituting a . for the %w ) and then it works.  But not sure if there are other possible date string formats that might come back from Google Play (different GEO stores perhaps?) that this would then break on.

I will say that I was unable to get this to work as part of your tutorial on IAP purchases, Rob.

I am horrible with regular expressions, but neither of the patterns that you have there match what I am getting back from the Google Play store today.

This is the string that I just got back as the transaction date:

Tue Jan 07 01:06:53 GMT+00:00 2014

Both of the patterns fail with all fields being nil.  And not sure why, because everything I have seen would indicate that this pattern would work for that string.

Try:

function M.makeTimeStamp(dateString, mode)     local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)([%+%-])(%d+)%:(%d+)"     local xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin     local monthLookup = {Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12}     local convertedTimestamp     local offset = 0     if mode and mode == "ctime" then         pattern = "%w+ (%w+) (%d+) (%d+):(%d+):(%d+) (%w+) (%d+)"         local monthName, TZName         monthName, xday, xhour, xminute, xseconds, TZName, xyear = dateString:match(pattern)         xmonth = monthLookup[monthName]         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})     else         xyear, xmonth, xday, xhour, xminute, xseconds, xoffset, xoffsethour, xoffsetmin = dateString:match(pattern)         convertedTimestamp = os.time({year = xyear, month = xmonth,         day = xday, hour = xhour, min = xminute, sec = xseconds})         offset = xoffsethour \* 60 + xoffsetmin         if xoffset == "-" then offset = offset \* -1 end     end     return convertedTimestamp + offset end

That above date works with dates that have Z timezone info, not +offset type dates.  This version should work (pulled it from code I use in my IAP based apps)…

Rob