在任何编程语言中处理“时间”最初都可能具有挑战性,因为各种时间/日期函数的含义和行为方式并不总是显而易见的。本教程将讨论其中一些问题,并向您展示如何处理日期计算、时区和日期格式等内容。
在开始编写代码之前,有几个重要的概念需要理解。对于计算机来说,时间的基数单位是**秒**。我们可以从这一个值确定任何日期,或者使用分数,甚至更小的时间度量。
虽然一秒对于人类来说是很短的一段时间,但对于计算机来说却很长。正如人类将长时间分解成更小的块一样,计算机也是如此。除了**秒**之外,许多函数以**毫秒**
为单位工作。在 Corona 中,system.getTimer() 调用返回应用程序开始运行以来的时间量,该值通常以**毫秒**返回,如果硬件支持,则小数部分表示微秒。大多数设备将返回如下所示的小数时间:
1839.3949
对于帧率为每秒 30 或 60 帧(1/30 秒到 1/60 秒)的 Corona 应用程序,分辨率高于 1/1000 秒并不重要。因此,我们使用以**毫秒**运行的函数,包括
由于这些函数都接受以毫秒为单位的时间,因此,例如,您将为该函数提供值 `5000` 来表示 5 秒。½ 秒将是 `500`,2½ 秒将是 `2500`,依此类推。基本上,只需将您想要的时间(以秒为单位)乘以 `1000` 即可获得这些函数的任何一个的时间。
如上所述,计算机的基本时间单位是秒。iOS 和 Android 以及 macOS 都基于源自 Unix 的操作系统,在这些操作系统中,标准“时间”函数返回自
在 Corona 中,要获取自
print( os.time() )
这将输出类似 `1497577639` 的内容。这个数字本身没有什么意义,您无法真正确定它所代表的“现实世界”时间,但它对于计算**日期数学**非常有用。例如,假设您正在构建一个
player[1].lastMove = os.time()
然后,如果您想检查他们在过去一小时内是否进行了移动,您可以编写
local now = os.time() if ( now > ( player[1].lastMove + 3600 ) ) then -- Nudge the player end
`3600` 是从哪里来的?很简单!`3600` 是 60 秒乘以 60 分钟,即一小时。
本质上,将时间(以秒为单位)作为整数值,进行日期数学运算就变得非常容易
24 * 60 * 60
)7 * 24 * 60 * 60
)30 * 24 * 60 * 60
)日期处理起来有点 challenging ,因为它们是**字符串**,可以用看似无限的方式格式化,包括
2010 年 4 月 1 日 下午 4:53
2010 年 4 月 1 日 下午 4:53
10/4/1 16:53 MT
2013 年 1 月 13 日星期日下午 3:17:32 EST
13-1 月-13 15:17
作为开发人员,您需要将日期解析为它们的
一种常见的日期格式是
2017-01-12T12:04:35.03-0400
这可能看起来有点吓人,所以让我们将这些元素分开来进一步检查
2017-01-12 T 12:04:35.03 -0400
好多了!现在每个元素代表什么更清楚了
`T` 之前的部分是日期,采用非常可预测且
字母 `T` 表示**时间**部分的开始;之后是另一系列正整数,表示**小时**、**分钟**和**秒**,用冒号分隔。请注意,**秒**值可以是表示整数加小数秒的浮点数。
最后,字符串可能有一个可选的**时区**字符串,指示时间 originated 的区域。我们稍后将详细讨论时区格式。
要将
local dateString = "2017-01-12T12:04:35.03-0400" local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%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 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
考虑时区非常重要,因为默认情况下,`os.time()` 返回的值是相对于您所在时区的本地时间。您可以轻松地将“现在”与时间戳进行比较,以确定某事件是在过去还是将来,或者是否已经过了给定的时间量。
在日期字符串中,结尾字符 `Z` 表示时间采用**协调世界时**或**UTC**。如果采用 UTC 或本地时间,则无需进行任何时区调整。
这是一个完整的函数,它结合了本节中讨论的各个方面
local function makeTimeStamp( dateString ) local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%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
尽管功能强大且方便,但此代码**不**补偿夏令时,这超出了本教程的范围。
在某些时候,您可能需要对时间进行“反向”操作,并将其转换为用户可以理解的格式的日期字符串。这就是 os.date() 函数的目的。
`os.date()` 函数接受两个可选参数。在不带参数的情况下调用它将返回您所在时区(或您的设备认为您所在时区)的当前日期/时间。这将采用如下格式
Sat Jan 12 14:07:30 2013
幸运的是,您可以指定各种格式参数来根据需要构建日期。这些格式参数基于 Unix/C++ 库函数 strftime,您可以使用它以多种不同方式格式化日期/时间。
print( os.date("%A") ) -- Outputs a string representing the weekday print( os.date("%A %l:%M%p") ) -- Outputs something like "Saturday 2:30PM"
默认情况下,os.date() 返回的值将基于您的语言环境或时区。如果您想要创建上述类型的日期(可能是为 located 于不同时区的玩家的多人游戏),那么理解这一点至关重要。在这种情况下,您需要通过在 `format` 参数前面放置一个 `!` 来输出基于**UTC**的时间
print( os.date("!%Y-%m-%dT%XZ") ) -- In UTC; outputs something like "2017-06-16T19:32:23Z"
处理时间和日期可能在语法上比较繁琐,但希望本教程已经表明这不是一项不可克服的任务。稍加努力并使用上述便捷的函数/方法,您就可以以过去可能没有想过的方式“掌控时间”。