标签 日期 下的文章

需要知道重要事件发生前有多少天吗?让 Linux bash 和 date 命令可以帮助你!

随着即将来临的重要假期,你可能需要提醒你还要准备多久。

幸运的是,你可以从 date 命令获得很多帮助。在本篇中,我们将研究 date 和 bash 脚本如何告诉你从今天到你预期的事件之间有多少天。

首先,在进行之前有几个提示。date 命令的 %j 选项将以 1 至 366 之间的数字显示当前日期。如你所想的一样,1 月 1 日将显示为 1,12 月 31 日将显示为 365 或 366,这取决于是否是闰年。继续尝试。你应该会看到以下内容:

$ date +%j
339

但是,你可以通过以下方式,在 date 命令中得到一年中任何一天的数字:

$ date -d "Mar 18" +%j
077

要记住的是,即使该日期是过去的日期,上面命令也会向你显示当年的日期。但是,你可以在命令中添加年来修复该问题:

$ date -d "Apr 29" +%j
119
$ date -d "Apr 29 2020" +%j
120

在闰年中,4 月 29 日将是一年的 120 天,而不是 119 天。

如果你想倒数圣诞节之前的日子并且不想在挂历上留下指纹,你可以使用以下脚本:

#!/bin/sh

XMAS=`date -d "Dec 25" +%j`
TODAY=`date +%j`
DAYS=$(($XMAS - $TODAY))

case $DAYS in
  0) echo "It's today! Merry Christmas!";;
  [0-9]*) echo "$DAYS days remaining";;
  -[0-9]*) echo "Oops, you missed it";;
esac

在此脚本中,我们获取 12 月 25 日和今天的日期,然后相减。如果结果是正数,我们将显示剩余天数。如果为零,则发出 “Merry Christmas” 的消息,如果为负,那么仅告诉运行脚本的人他们错过了假期。也许他们沉迷在蛋酒中了。

case 语句由用来打印信息的语句组成,当剩余时间等于 0,或任意数字或以 - 符号开头的数字(也就是过去)分别打印不同的信息。

对于人们想要关注的任何日期,都可以使用相同方法。实际上,我们可以要求运行脚本的人员提供日期,然后让他们知道从现在到那天还有多少天。这个脚本是这样的。

#!/bin/sh

echo -n "Enter event date (e.g., June 6): "
read dt
EVENT=`date -d "$dt" +%j`
TODAY=`date +%j`
DAYS=`expr $EVENT - $TODAY`

case $DAYS in
  0) echo "It's today!";;
  [0-9]*) echo "$DAYS days remaining";;
  -[0-9]*) echo "Oops, you missed it";;
esac

使用此脚本会遇到的一个问题,如果运行该脚本的人希望知道到第二年这个特殊日子还有多少天,他们会感到失望。即使他们输入日期时提供了年,date -d 命令仍将仅提供今年中的天数,而不会提供从现在到那时的天数。

计算从今天到某年的日期之间的天数可能有些棘手。你需要包括所有中间年份,并注意那些闰年。

使用 Unix 纪元时间

计算从现在到某个特殊日期之间的天数的另一种方法是利用 Unix 系统存储日期的方法。如果将自 1970 年 1 月 1 日开始的秒数转换为天数,那么就可以很容易地执行此操作,如下脚本所示:

#!/bin/bash

echo -n "Enter target date (e.g., Mar 18 2021)> "
read target_date
today=`echo $(($(date --utc --date "$1" +%s)/86400))`
target=`echo $(($(date --utc --date "$target_date" +%s)/86400))`
days=`expr $target - $today`
echo "$days days until $target_date"

解释一下,86400 是一天中的秒数。将自 Unix 纪元开始以来的秒数除该数即为天数。

$ ./countdown
Enter target date (e.g., Mar 18 2021)> Mar 18 2020
104 days until Mar 18 2020

via: https://www.networkworld.com/article/3487712/counting-down-the-days-using-bash.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux 的 date 命令提供了很多显示日期和时间的选项,要比你想的还要多。这是一些有用的选择。

在 Linux 系统上,date 命令非常简单。你键入 date,日期和时间将以一种有用的方式显示。它包括星期几、日期、时间和时区:

$ date
Tue 26 Nov 2019 11:45:11 AM EST

只要你的系统配置正确,你就会看到日期和当前时间以及时区。

但是,该命令还提供了许多选项来以不同方式显示日期和时间信息。例如,如果要显示日期以便进行排序,则可能需要使用如下命令:

$ date "+%Y-%m-%d"
2019-11-26

在这种情况下,年、月和日按该顺序排列。请注意,我们使用大写字母 Y 来获得四位数的年份。如果我们使用小写的 y,则只会看到两位数字的年份(例如 19)。不要让这种做法使你错误地联想到如果 %m 给你一个数字月份,%M 可能会给你月份的名称。不,%M 将给你分钟数。要以缩写名称格式获得月份,你要使用 %b,而对于完全拼写的月份,则要使用 %B

$ date "+%b %B"
Nov November

或者,你可能希望以这种常用格式显示日期:

$ date "+%D"
11/26/19

如果你需要四位数的年份,则可以执行以下操作:

$ date "+%x"
11/26/2019

下面是一个可能有用的示例。假设你需要创建一个每日报告并在文件名中包含日期,则可以使用以下命令来创建文件(可能用在脚本中):

$ touch Report-`date "+%Y-%m-%d"`

当你列出你的报告时,它们将按日期顺序或反向日期顺序(如果你添加 -r)列出。

$ ls -r Report*
Report-2019-11-26
Report-2019-11-25
Report-2019-11-22
Report-2019-11-21
Report-2019-11-20

你还可以在日期字符串中添加其他详细信息。可用的各种选项多得令人惊讶。你可以使用 date "+%q" 来显示你所在的一年中的哪个季度,或使用类似以下命令来显示两个月前的日期:

$ date --date="2 months ago"
Thu 26 Sep 2019 09:02:43 AM EDT

是否想知道下周四的日期?你可以使用类似 date --date="next thu" 的命令,但是要理解,对于Linux,下个周四意味着今天之后的周四。如果今天是星期三,那就是明天,而不是下周的星期四。但是,你可以像下面的第二个命令一样指定下周的星期四。

$ date --date="next thu"
Thu 28 Nov 2019 12:00:00 AM EST
$ date --date="next week thu"
Thu 05 Dec 2019 12:00:00 AM EST

date 命令的手册页列出了其所有选项。该列表多得令人难以置信,但是你可能会发现一些日期/时间显示选项非常适合你。以下是一些你可能会发现有趣的东西。

世界标准时间(UTC):

$ date -u
Tue 26 Nov 2019 01:13:59 PM UTC

自 1970 年 1 月 1 日以来的秒数(与 Linux 系统上日期的存储方式有关):

$ date +%s
1574774137

以下是 date 命令选项的完整列表。正如我所说,它比我们大多数人想象的要广泛得多。

  • %% 显示字母 %
  • %a 本地语言环境的缩写星期名称(例如,日 / Sun)
  • %A 本地语言环境的完整星期名称(例如,星期日 / Sunday)
  • %b 本地语言环境的缩写月份名称(例如 一 / Jan)
  • %B 本地语言环境的完整月份名称(例如,一月 / January)
  • %c 本地语言环境的日期和时间(例如 2005年3月3日 星期四 23:05:25 / Thu Mar 3 23:05:25 2005)
  • %C 世纪;类似于 %Y,但省略了后两位数字(例如,20)
  • %d 月份的天(例如,01)
  • %D 日期;与 %m/%d/%y 相同
  • %e 月份的天,填充前缀空格;与 %_d 相同
  • %F 完整日期;与 %Y-%m-%d 相同
  • %g ISO 周号的年份的后两位数字(请参见 %G
  • %G ISO 周号的年份(请参阅 %V);通常仅配合 %V 使用
  • %h%b 相同
  • %H 24 小时制的小时(00..23)
  • %I 12 小时制的小时(01..12)
  • %j 一年的天(001..366)
  • %k 24 小时制的小时,填充前缀空格( 0..23);与 %_H 相同
  • %l 12 小时制的小时,填充前缀空格( 1..12);与 %_I 相同
  • %m 月份(01..12)
  • %M 分钟(00..59)
  • %n 换行符
  • %N 纳秒(000000000..999999999)
  • %p 本地语言环境中等同于 AM 或 PM 的字符串;如果未知,则为空白
  • %P%p,但使用小写
  • %q 季度(1..4)
  • %r 本地语言环境的 12 小时制时间(例如,晚上 11:11:04 / 11:11:04 PM)
  • %R 24 小时制的小时和分钟;与 %H:%M 相同
  • %s 自 1970-01-01 00:00:00 UTC 以来的秒数
  • %S 秒(00..60)
  • %t 制表符
  • %T 时间;与 %H:%M:%S 相同
  • %u 星期(1..7);1 是星期一
  • %U 年的周号,以星期日为一周的第一天,从 00 开始(00..53)
  • %V ISO 周号,以星期一为一周的第一天,从 01 开始(01..53)
  • %w 星期(0..6);0 是星期日
  • %W 年的周号,星期一为一周的第一天,从 00 开始(00..53)
  • %x 本地语言环境的日期表示形式(例如,1999年12月31日 / 12/31/99)
  • %X 本地语言环境的时间表示形式(例如,23:13:48)
  • %y 年的最后两位数字(00..99)
  • %Y 年份
  • %z +hhmm 格式的数字时区(例如,-0400)
  • %:z +hh:mm 格式的数字时区(例如,-04:00)
  • %::z +hh:mm:ss 格式的数字时区(例如,-04:00:00)
  • %:::z 数字时区,: 指明精度(例如,-04, +05:30)
  • %Z 字母时区缩写(例如,EDT)

via: https://www.networkworld.com/article/3481602/displaying-dates-and-times-your-way-with-linux.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:wxy 校对:校对者ID

本文由 LCTT 原创编译,Linux中国 荣誉推出

在 Python 中有许多库可以很容易地测试、转换和读取日期和时间信息。

这篇文章是与 Jeff Triplett 一起合写的。

曾几何时,我们中的一个人(Lacey)盯了一个多小时的 Python 文档中描述日期和时间格式化字符串的表格。当我试图编写从 API 中将日期时间字符串转换为 Python datetime 对象时,我很难理解其中的特定部分,因此我决定请求帮助。

有人问道:“为什么你不使用 dateutil 呢?”

读者,如果你没有从这个月的 Python 专栏中获得任何东西,只是学习到有比 datetime 的 strptime 更容易地将 datetime 字符串转换为 datetime 对象的方法,那么我们觉得就已经成功了。

但是,除了将字符串转换为更有用的 Python 对象之外,还有许多库都有一些有用的方法和工具,可以让您更轻松地进行时间测试、将时间转换为不同的时区、以人类可读的格式传递时间信息,等等。如果这是你在 Python 中第一次接触日期和时间,请暂停并阅读 如何使用 Python的日期和时间 。要理解为什么在编程中处理日期和时间是困难的,请阅读 愚蠢的程序员相信时间

这篇文章将会向你介绍以下库:

随意跳过那些你已经熟悉的库,专注于那些对你而言是新的库。

内建的 datetime 模块

在跳转到其他库之前,让我们回顾一下如何使用 datetime 模块将日期字符串转换为 Python datetime 对象。

假设我们从 API 接受到一个日期字符串,并且需要它作为 Python datetime 对象存在:

2018-04-29T17:45:25Z

这个字符串包括:

  • 日期是 YYYY-MM-DD 格式的
  • 字母 T 表示时间即将到来
  • 时间是 HH:II:SS 格式的
  • 表示此时间的时区指示符 Z 采用 UTC (详细了解日期时间字符格式

要使用 datetime 模块将此字符串转换为 Python datetime 对象,你应该从 strptime 开始。 datetime.strptime 接受日期字符串和格式化字符并返回一个 Python datetime 对象。

我们必须手动将日期时间字符串的每个部分转换为 Python 的 datetime.strptime 可以理解的合适的格式化字符串。四位数年份由 %Y 表示,两位数月份是 %m,两位数的日期是 %d。在 24 小时制中,小时是 %H,分钟是 %M,秒是 %S

为了得出这些结论,需要在Python 文档的表格中多加注意。

由于字符串中的 Z 表示此日期时间字符串采用 UTC,所以我们可以在格式中忽略此项。(现在,我们不会担心时区。)

转换的代码是这样的:

$ from datetime import datetime 
$ datetime.strptime('2018-04-29T17:45:25Z', '%Y-%m-%dT%H:%M:%SZ')
datetime.datetime(2018, 4, 29, 17, 45, 25)

格式字符串很难阅读和理解。我必须手动计算原始字符串中的字母 T 和 “Z”的位置,以及标点符号和格式化字符串,如 %S%m。有些不太了解 datetime 的人阅读我的代码可能会发现它很难理解,尽管其含义已有文档记载,但它仍然很难阅读。

让我们看看其他库是如何处理这种转换的。

Dateutil

dateutil 模块datetime 模块做了一些扩展。

继续使用上面的解析示例,使用 dateutil 实现相同的结果要简单得多:

$ from dateutil.parser import parse
$ parse('2018-04-29T17:45:25Z')
datetime.datetime(2018, 4, 29, 17, 45, 25, tzinfo=tzutc())

如果字符串包含时区,那么 dateutil 解析器会自动返回字符串的时区。由于我们在 UTC 时区,你可以看到返回来一个 datetime 对象。如果你想解析完全忽略时区信息并返回原生的 datetime 对象,你可以传递 ignoretz=True 来解析,如下所示:

$ from dateutil.parser import parse
$ parse('2018-04-29T17:45:25Z', ignoretz=True)
datetime.datetime(2018, 4, 29, 17, 45, 25)

dateutil 还可以解析其他人类可读的日期字符串:

$ parse('April 29th, 2018 at 5:45 pm')
datetime.datetime(2018, 4, 29, 17, 45)

dateutil 还提供了像 relativedelta 的工具,它用于计算两个日期时间之间的时间差或向日期时间添加或删除时间,rrule 创建重复日期时间,tz 用于解决时区以及其他工具。

Arrow

Arrow 是另一个库,其目标是操作、格式化,以及处理对人类更友好的日期和时间。它包含 dateutil,根据其文档,它旨在“帮助你使用更少的包导入和更少的代码来处理日期和时间”。

要返回我们的解析示例,下面介绍如何使用 Arrow 将日期字符串转换为 Arrow 的 datetime 类的实例:

$ import arrow 
$ arrow.get('2018-04-29T17:45:25Z')
<Arrow [2018-04-29T17:45:25+00:00]>

你也可以在 get() 的第二个参数中指定格式,就像使用 strptime 一样,但是 Arrow 会尽力解析你给出的字符串,get() 返回 Arrow 的 datetime 类的一个实例。要使用 Arrow 来获取 Python datetime 对象,按照如下所示链式 datetime:

$ arrow.get('2018-04-29T17:45:25Z').datetime
datetime.datetime(2018, 4, 29, 17, 45, 25, tzinfo=tzutc())

通过 Arrow datetime 类的实例,你可以访问 Arrow 的其他有用方法。例如,它的 humanize() 方法将日期时间翻译成人类可读的短语,就像这样:

$ import arrow
$ utc = arrow.utcnow()
$ utc.humanize()
'seconds ago'

在 Arrow 的文档中阅读更多关于其有用方法的信息。

Moment

Moment 的作者认为它是“内部测试版”,但即使它处于早期阶段,它也是非常受欢迎的,我们想来讨论它。

Moment 的方法将字符转换为其他更有用的东西很简单,类似于我们之前提到的库:

$ import moment
$ moment.date('2018-04-29T17:45:25Z')
<Moment(2018-04-29T17:45:25)>

就像其他库一样,它最初返回它自己的 datetime 类的实例,要返回 Python datetime 对象,添加额外的 date() 调用即可。

$ moment.date('2018-04-29T17:45:25Z').date
datetime.datetime(2018, 4, 29, 17, 45, 25, tzinfo=<StaticTzInfo 'Z'>)

这将 Moment datetime 类转换为 Python datetime 对象。

Moment 还提供了使用人类可读的语言创建新日期的方法。例如创建一个明天的日期:

$ moment.date("tomorrow")
<Moment(2018-04-06T11:24:42)>

它的 add()subtract() 命令使用关键字参数来简化日期的操作。为了获得后天,Moment 会使用下面的代码:

$ moment.date("tomorrow").add(days=1)
<Moment(2018-04-07T11:26:48)>

Maya

Maya 包含了 Python 中其他流行处理日期时间的库,包括 Humanize、 pytz 和 pendulum 等等。这个项目旨在让人们更容易处理日期。

Maya 的 README 包含几个有用的实例。以下是如何使用 Maya 来重新处理以前的解析示例:

$ import maya
$ maya.parse('2018-04-29T17:45:25Z').datetime()
datetime.datetime(2018, 4, 29, 17, 45, 25, tzinfo=<UTC>)

注意我们必须在 maya.parse() 之后调用 datetime()。如果我们跳过这一步,Maya 将会返回一个 MayaDT 类的示例:<MayaDT epoch=1525023925.0>

由于 Maya 与 datetime 库中很多有用的方法重叠,因此它可以使用 MayaDT 类的实例执行诸如使用 slang_time() 方法将时间偏移量转换为纯文本语言,并将日期时间间隔保存在单个类的实例中。以下是如何使用 Maya 将日期时间表示为人类可读的短语:

$ import maya
$ maya.parse('2018-04-29T17:45:25Z').slang_time()
'23 days from now

显然,slang_time() 的输出将根据距离 datetime 对象相对较近或较远的距离而变化。

Delorean

Delorean,以 《返回未来》 电影中的时间旅行汽车命名,它对于操纵日期时间特别有用,包括将日期时间转换为其他时区并添加或减去时间。

Delorean 需要有效的 Python datetime 对象才能工作,所以如果你需要使用时间字符串,最好将其与上述库中的一个配合使用。例如,将 Maya 与 Delorean 一起使用:

$ import maya 
$ d_t = maya.parse('2018-04-29T17:45:25Z').datetime()

现在,你有了一个 datetime 对象 d\_t,你可以使用 Delorean 来做一些事情,例如将日期时间转换为美国东部时区:

$ from delorean import Delorean
$ d = Delorean(d_t)
$ d
Delorean(datetime=datetime.datetime(2018, 4, 29, 17, 45, 25), timezone='UTC')
$ d.shift('US/Eastern')
Delorean(datetime=datetime.datetime(2018, 4, 29, 13, 45, 25), timezone='US/Eastern')

看到小时是怎样从 17 变成 13 了吗?

你也可以使用自然语言方法来操作 datetime 对象。获取 2018 年 4 月 29 日之后的下个星期五(我们现在使用的):

$ d.next_friday()
Delorean(datetime=datetime.datetime(2018, 5, 4, 13, 45, 25), timezone='US/Eastern')

在 Delorean 的文档中阅读更多关于其的用法。

Freezegun

Freezegun 是一个可以帮助你在 Python 代码中测试特定日期的库。使用 @freeze_time 装饰器,你可以为测试用例设置特定的日期和时间,并且所有对 datetime.datetime.now()datetime.datetime.utcnow() 等的调用都将返回你指定的日期和时间。例如:

from freezegun import freeze_time
import datetime

@freeze_time("2017-04-14")
def test(): 
    assert datetime.datetime.now() == datetime.datetime(2017, 4, 14)

要跨时区进行测试,你可以将 tz_offset 参数传递给装饰器。freeze_time 装饰器也接受更简单的口语化日期,例如 @freeze_time('April 4, 2017')


上面提到的每个库都提供了一组不同的特性和功能,也许很难决定哪一个最适合你的需要。Maya 的作者, Kenneth Reitz 说到:“所有这些项目相辅相成,它们都是我们的朋友”。

这些库共享一些功能,但不是全部。有些擅长时间操作,有些擅长解析,但它们都有共同的目标,即让你对日期和时间的工作更轻松。下次你发现自己对 Python 的内置 datetime 模块感到沮丧,我们希望你可以选择其中的一个库进行试验。


via: https://opensource.com/article/18/4/python-datetime-libraries

作者: Lacey Williams Hensche 选题: lujun9972 译者: MjSeven 校对: wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在本文中, 我们会通过一些案例来演示如何使用 Linux 中的 date 命令。date 命令可以用户输出/设置系统日期和时间。 date 命令很简单, 请参见下面的例子和语法。

默认情况下,当不带任何参数运行 date 命令时,它会输出当前系统日期和时间:

$ date
Sat  2 Dec 12:34:12 CST 2017

语法

Usage: date [OPTION]... [+FORMAT]
  or:  date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
以给定格式显示当前时间,或设置系统时间。

案例

下面这些案例会向你演示如何使用 date 命令来查看前后一段时间的日期时间。

1、 查找 5 周后的日期

date -d "5 weeks"
Sun Jan  7 19:53:50 CST 2018

2、 查找 5 周后又过 4 天的日期

date -d "5 weeks 4 days"
Thu Jan 11 19:55:35 CST 2018

3、 获取下个月的日期

date -d "next month"
Wed Jan  3 19:57:43 CST 2018

4、 获取下周日的日期

date -d last-sunday
Sun Nov 26 00:00:00 CST 2017

date 命令还有很多格式化相关的选项, 下面的例子向你演示如何格式化 date 命令的输出.

5、 以 yyyy-mm-dd 的格式显示日期

date +"%F"
2017-12-03

6、 以 mm/dd/yyyy 的格式显示日期

date +"%m/%d/%Y"
12/03/2017

7、 只显示时间

date +"%T"
20:07:04

8、 显示今天是一年中的第几天

date +"%j"
337

9、 与格式化相关的选项

格式说明
%%显示百分号 (%)。
%a星期的缩写形式 (如: Sun)。
%A星期的完整形式 (如: Sunday)。
%b缩写的月份 (如: Jan)。
%B当前区域的月份全称 (如: January)。
%c日期以及时间 (如: Thu Mar 3 23:05:25 2005)。
%C当前世纪;类似 %Y, 但是会省略最后两位 (如: 20)。
%d月中的第几日 (如: 01)。
%D日期;效果与 %m/%d/%y 一样。
%e月中的第几日, 会填充空格;与 %_d 一样。
%F完整的日期;跟 %Y-%m-%d 一样。
%g年份的后两位 (参见 %G)。
%G年份 (参见 %V);通常跟 %V 连用。
%h%b
%H小时 (00..23)。
%I小时 (01..12)。
%j一年中的第几天 (001..366)。
%k小时, 用空格填充 ( 0..23); 与 %_H 一样。
%l小时, 用空格填充 ( 1..12); 与 %_I 一样。
%m月份 (01..12)。
%M分钟 (00..59)。
%n换行。
%N纳秒 (000000000..999999999)。
%p当前区域时间是上午 AM 还是下午 PM;未知则为空。
%P类似 %p, 但是用小写字母显示。
%r当前区域的 12 小时制显示时间 (如: 11:11:04 PM)。
%R24 小时制的小时和分钟;同 %H:%M
%s从 1970-01-01 00:00:00 UTC 到现在经历的秒数。
%S秒数 (00..60)。
%t制表符。
%T时间;同 %H:%M:%S
%u星期 (1..7);1 表示 星期一
%U一年中的第几个星期,以周日为一周的开始 (00..53)。
%V一年中的第几个星期,以周一为一周的开始 (01..53)。
%w用数字表示周几 (0..6); 0 表示 周日
%W一年中的第几个星期, 周一为一周的开始 (00..53)。
%x当前区域的日期表示(如: 12/31/99)。
%X当前区域的时间表示 (如: 23:13:48)。
%y年份的后面两位 (00..99)。
%Y年。
%z+hhmm 的数字格式表示时区 (如: -0400)。
%:z+hh:mm 的数字格式表示时区 (如: -04:00)。
%::z+hh:mm:ss 的数字格式表示时区 (如: -04:00:00)。
%:::z以数字格式表示时区, 其中 : 的个数由你需要的精度来决定 (例如, -04+05:30)。
%Z时区的字符缩写(例如, EDT)。

10、 设置系统时间

你也可以使用 date 来手工设置系统时间,方法是使用 --set 选项, 下面的例子会将系统时间设置成 2017 年 8 月 30 日下午 4 点 22 分。

date --set="20170830 16:22"

当然, 如果你使用的是我们的 VPS 托管服务,你总是可以联系并咨询我们的 Linux 专家管理员(通过客服电话或者下工单的方式)关于 date 命令的任何东西。他们是 24×7 在线的,会立即向您提供帮助。(LCTT 译注:原文的广告~)

PS. 如果你喜欢这篇帖子,请点击下面的按钮分享或者留言。谢谢。


via: https://www.rosehosting.com/blog/use-the-date-command-in-linux/

作者:rosehosting 译者:lujun9972 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

当你需要保存日期时间数据时,一个问题来了:你应该使用 MySQL 中的什么类型?使用 MySQL 原生的 DATE 类型还是使用 INT 字段把日期和时间保存为一个纯数字呢?

在这篇文章中,我将解释 MySQL 原生的方案,并给出一个最常用数据类型的对比表。我们也将对一些典型的查询做基准测试,然后得出在给定场景下应该使用什么数据类型的结论。

如果你想直接看结论,请翻到文章最下方。

原生的 MySQL Datetime 数据类型

Datetime 数据表示一个时间点。这可以用作日志记录、物联网时间戳、日历事件数据,等等。MySQL 有两种原生的类型可以将这种信息保存在单个字段中:Datetime 和 Timestamp。MySQL 文档中是这么介绍这些数据类型的:

DATETIME 类型用于保存同时包含日期和时间两部分的值。MySQL 以 'YYYY-MM-DD HH:MM:SS' 形式接收和显示 DATETIME 类型的值。

TIMESTAMP 类型用于保存同时包含日期和时间两部分的值。

DATETIME 或 TIMESTAMP 类型的值可以在尾部包含一个毫秒部分,精确度最高到微秒(6 位数)。

TIMESTAMP 和 DATETIME 数据类型提供自动初始化和更新到当前的日期和时间的功能,只需在列的定义中设置 DEFAULT CURRENTTIMESTAMP 和 ON UPDATE CURRENTTIMESTAMP。

作为一个例子:

CREATE TABLE `datetime_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `measured_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `measured_on` (`measured_on`)
) ENGINE=InnoDB;
CREATE TABLE `timestamp_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `measured_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `measured_on` (`measured_on`)
) ENGINE=InnoDB;

除了原生的日期时间表示方法,还有另一种常用的存储日期和时间信息的方法。即使用 INT 字段保存 Unix 时间(从1970 年 1 月 1 日协调世界时(UTC)建立所经过的秒数)。

MySQL 也提供了只保存时间信息中的一部分的方式,通过使用 Date、Year 或 Time 类型。由于这篇文章是关于保存准确时间点的最佳方式的,我们没有讨论这些不那么精确的局部类型。

使用 INT 类型保存 Unix 时间

使用一个简单的 INT 列保存 Unix 时间是最普通的方法。使用 INT,你可以确保你要保存的数字可以快速、可靠地插入到表中,就像这样:

INSERT INTO `vertabelo`.`sampletable`
(
 `id`,
 `measured_on` ### INT 类型的列
)
VALUES
(
 1,
 946684801
 ### 至 01/01/2000 @ 12:00am (UTC) 的 UNIX 时间戳 http://unixtimestamp.com
);

这就是关于它的所有内容了。它仅仅是个简单的 INT 列,MySQL 的处理方式是这样的:在内部使用 4 个字节保存那些数据。所以如果你在这个列上使用 SELECT 你将会得到一个数字。如果你想把这个列用作日期进行比较,下面的查询并不能正确工作:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
    measured_on > '2016-01-01' ### measured_on 会被作为字符串比较以进行查询
LIMIT 5;

这是因为 MySQL 把 INT 视为数字,而非日期。为了进行日期比较,你必须要么获取( LCTT 译注:从 1970-01-01 00:00:00)到 2016-01-01 经过的秒数,要么使用 MySQL 的 FROM\_UNIXTIME() 函数把 INT 列转为 Date 类型。下面的查询展示了 FROM\_UNIXTIME() 函数的用法:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
    FROM_UNIXTIME(measured_on) > '2016-01-01'
LIMIT 5;

这会正确地获取到日期在 2016-01-01 之后的记录。你也可以直接比较数字和 2016-01-01 的 Unix 时间戳表示形式,即 1451606400。这样做意味着不用使用任何特殊的函数,因为你是在直接比较数字。查询如下:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
   measured_on > 1451606400
LIMIT 5;

假如这种方式不够高效甚至提前做这种转换是不可行的话,那该怎么办?例如,你想获取 2016 年所有星期三的记录。要做到这样而不使用任何 MySQL 日期函数,你就不得不查出 2016 年每个星期三的开始和结束时间的 Unix 时间戳。然后你不得不写很大的查询,至少要在 WHERE 中包含 104 个比较。(2016 年有 52 个星期三,你不得不考虑一天的开始(0:00 am)和结束(11:59:59 pm)...)

结果是你很可能最终会使用 FROM\_UNIXTIME() 转换函数。既然如此,为什么不试下真正的日期类型呢?

使用 Datetime 和 Timestamp

Datetime 和 Timestamp 几乎以同样的方式工作。两种都保存日期和时间信息,毫秒部分最高精确度都是 6 位数。同时,使用人类可读的日期形式如 "2016-01-01" (为了便于比较)都能工作。查询时两种类型都支持“宽松格式”。宽松的语法允许任何标点符号作为分隔符。例如,"YYYY-MM-DD HH:MM:SS" 和 "YY-MM-DD HH:MM:SS" 两种形式都可以。在宽松格式情况下以下任何一种形式都能工作:

2012-12-31 11:30:45
2012^12^31 11+30+45
2012/12/31 11*30*45
2012@12@31 11^30^45

其它宽松格式也是允许的;你可以在 MySQL 参考手册 找到所有的格式。

默认情况下,Datetime 和 Timestamp 两种类型查询结果都以标准输出格式显示 —— 年-月-日 时:分:秒 (如 2016-01-01 23:59:59)。如果使用了毫秒部分,它们应该以小数值出现在秒后面 (如 2016-01-01 23:59:59.5)。

Timestamp 和 Datetime 的核心不同点主要在于 MySQL 在内部如何表示这些信息:两种都以二进制而非字符串形式存储,但在表示日期/时间部分时 Timestamp (4 字节) 比 Datetime (5 字节) 少使用 1 字节。当保存毫秒部分时两种都使用额外的空间 (1-3 字节)。如果你存储 150 万条记录,这种 1 字节的差异是微不足道的:

150 万条记录 * 每条记录 1 字节 / (1048576 字节/MB) = 1.43 MB

Timestamp 节省的 1 字节是有代价的:你只能存储从 '1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999' 之间的时间。而 Datetime 允许你存储从 '1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999' 之间的任何时间。

另一个重要的差别 —— 很多 MySQL 开发者没意识到的 —— 是 MySQL 使用服务器的时区转换 Timestamp 值到它的 UTC 等价值再保存。当获取值是它会再次进行时区转换,所以你得回了你“原始的”日期/时间值。有可能,下面这些情况会发生。

理想情况下,如果你一直使用同一个时区,MySQL 会获取到和你存储的同样的值。以我的经验,如果你的数据库涉及时区变换,你可能会遇到问题。例如,服务器变化(比如,你把数据库从都柏林的一台服务器迁移到加利福尼亚的一台服务器上,或者你只是修改了一下服务器的时区)时可能会发生这种情况。不管哪种方式,如果你获取数据时的时区是不同的,数据就会受影响。

Datetime 列不会被数据库改变。无论时区怎样配置,每次都会保存和获取到同样的值。就我而言,我认为这是一个更可靠的选择。

MySQL 文档:

MySQL 把 TIMESTAMP 值从当前的时区转换到 UTC 再存储,获取时再从 UTC 转回当前的时区。(其它类型如 DATETIME 不会这样,它们会“原样”保存。) 默认情况下,每个连接的当前时区都是服务器的时区。时区可以基于连接设置。只要时区设置保持一致,你就能得到和保存的相同的值。如果你保存了一个 TIMESTAMP 值,然后改变了时区再获取这个值,获取到的值和你存储的是不同的。这是因为在写入和查询的会话上没有使用同一个时区。当前时区可以通过系统变量 time\_zone 的值得到。更多信息,请查看 MySQL Server Time Zone Support

对比总结

在深入探讨使用各数据类型的性能差异之前,让我们先看一个总结表格以给你更多了解。每种类型的弱点以红色显示。

特性DatetimeTimestampInt (保存 Unix 时间)
原生时间表示否,所以大多数操作需要先使用转换函数,如 FROM\_UNIXTIME()
能保存毫秒是,最高 6 位精度是,最高 6 位精度
合法范围'1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999'1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999'若使用 unsigned, '1970-01-01 00:00:01.000000; 理论上最大到 '2106-2-07 06:28:15'
自动初始化(MySQL 5.6.5+)
宽松解释 (MySQL docs否,必须使用正确的格式
值被转换到 UTC 存储
可转换到其它类型是,如果值在合法的 Timestamp 范围中是,总是是,如果值在合法的范围中并使用转换函数
存储需求(MySQL 5.6.4+5 字节(如果使用了毫秒部分,再加最多 3 字节)4 字节 (如果使用了毫秒部分,再加最多 3 字节)4 字节 (不允许毫秒部分)
无需使用函数即可作为真实日期可读否,你必须格式化输出
数据分区是,使用 UNIX\_TIMESTAMP();在 MySQL 5.7 中其它表达式是不允许包含 TIMESTAMP 值的。同时,注意分区裁剪时的这些考虑是,使用 INT 上的任何合法操作

基准测试 INT、Timestamp 和 Datetime 的性能

为了比较这些类型的性能,我会使用我创建的一个天气预报网络的 150 万记录(准确说是 1,497,421)。这个网络每分钟都收集数据。为了让这些测试可复现,我已经删除了一些私有列,所以你可以使用这些数据运行你自己的测试。

基于我原始的表格,我创建了三个版本:

  • datetimemeasures 表在 measured_on 列使用 Datetime 类型,表示天气预报记录的测量时间
  • timestampmeasures 表在 measured_on 列使用 Timestamp 类型
  • inttimestampmeasures 表在 measured_on 列使用 INT (unsigned) 类型

这三个表拥有完全相同的数据;唯一的差别就是 measured_on 字段的类型。所有表都在 measured_on 列上设置了一个索引。

基准测试工具

为了评估这些数据类型的性能,我使用了两种方法。一种基于 Sysbench,它的官网是这么描述的:

... 一个模块化、跨平台和多线程的基准测试工具,用以评估那些对运行高负载数据库的系统非常重要的系统参数。

这个工具是 MySQL 文档中推荐的。

如果你使用 Windows (就像我),你可以下载一个包含可执行文件和我使用的测试查询的 zip 文件。它们基于 一种推荐的基准测试方法

为了执行一个给定的测试,你可以使用下面的命令(插入你自己的连接参数):

sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=sysbench_test_file.lua --num-threads=8 --max-requests=100 run

这会正常工作,这里 sysbench_test_file.lua 是测试文件,并包含了各个测试中指向各个表的 SQL 查询。

为了进一步验证结果,我也运行了 mysqlslap。它的官网是这么描述的:

mysqlslap 是一个诊断程序,为模拟 MySQL 服务器的客户端负载并报告各个阶段的用时而设计。它工作起来就像是很多客户端在同时访问服务器。”

记得这些测试中最重要的不是所需的绝对时间。而是在不同数据类型上执行相同查询时的相对时间。这两个基准测试工具的测试时间不一定相同,因为不同工具的工作方式不同。重要的是数据类型的比较,随着我们深入到测试中,这将会变得清楚。

基准测试

我将使用三种可以评估几个性能方面的查询:

  • 时间范围选择

    • 在 Datetime 和 Timestamp 数据类型上这允许我们直接比较而不需要使用任何特殊的日期函数。
    • 同时,我们可以评估在 INT 类型的列上使用日期函数相对于使用简单的数值比较的影响。为了做到这些我们需要把范围转换为 Unix 时间戳数值。
  • 日期函数选择

    • 与前个测试中比较操作针对一个简单的 DATE 值相反,这个测试使得我们可以评估使用日期函数作为 “WHERE” 子句的一部分的性能。
    • 我们还可以测试一个场景,即我们必须使用一个函数将 INT 列转换为一个合法的 DATE 类型然后执行查询。
  • count() 查询

    • 作为对前面测试的补充,这将评估在三种不同的表示类型上进行典型的统计查询的性能。

我们将在这些测试中覆盖一些常见的场景,并看到三种类型上的性能表现。

关于 SQL\_NO\_CACHE

当在查询中使用 SQL\_NO\_CACHE 时,服务器不使用查询缓存。它既不检查查询缓存以确认结果是不是已经在那儿了,也不会保存查询结果。因此,每个查询将反映真实的性能影响,就像每次查询都是第一次被调用。

测试 1:选择一个日期范围中的值

这个查询返回总计 1,497,421 行记录中的 75,706 行。

查询 1 和 Datetime:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.datetimemeasures m
WHERE
    m.measured_on > '2016-01-01 00:00:00.0'
      AND m.measured_on < '2016-02-01 00:00:00.0';

性能

响应时间 (ms)Sysbenchmysqlslap
最小152296
最大12613203
平均362809
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.datetimemeasures m WHERE m.measured_on > '2016-01-01 00:00:00.0' AND m.measured_on < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

查询 1 和 Timestamp:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.timestampmeasures m
WHERE
    m.measured_on > '2016-01-01 00:00:00.0'
        AND m.measured_on < '2016-02-01 00:00:00.0';

性能

响应时间 (ms)Sysbenchmysqlslap
最小214359
最大13893313
平均4311004
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.timestampmeasures m WHERE m.measured_on > '2016-01-01 00:00:00.0' AND m.measured_on < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

查询 1 和 INT:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    FROM_UNIXTIME(m.measured_on) > '2016-01-01 00:00:00.0'
        AND FROM_UNIXTIME(m.measured_on) < '2016-02-01 00:00:00.0';

性能

响应时间 (ms)Sysbenchmysqlslap
最小24727968
最大655410312
平均41078527
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE FROM_UNIXTIME(m.measured_on) > '2016-01-01 00:00:00.0' AND FROM_UNIXTIME(m.measured_on) < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

另一种 INT 上的查询 1:

由于这是个相当直接的范围搜索,而且查询中的日期可以轻易地转为简单的数值比较,我将它包含在了这个测试中。结果证明这是最快的方法 (你大概已经预料到了),因为它仅仅是比较数字而没有使用任何日期转换函数:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    m.measured_on > 1451617200
        AND m.measured_on < 1454295600;

性能

响应时间 (ms)Sysbenchmysqlslap
最小88171
最大2752157
平均165514
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=basic_int.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE m.measured_on > 1451617200 AND m.measured_on < 1454295600" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

测试 1 总结

平均响应时间 (ms)Sysbench相对于 Datetime 的速度mysqlslap相对于 Datetime 的速度
Datetime362-809-
Timestamp431慢 19%1004慢 24%
INT4107慢 1134%8527慢 1054%
另一种 INT 查询165快 55%514快 36%

两种基准测试工具都显示 Datetime 比 Timestamp 和 INT 更快。但 Datetime 没有我们在另一种 INT 查询中使用的简单数值比较快。

测试 2:选择星期一产生的记录

这个查询返回总计 1,497,421 行记录中的 221,850 行。

查询 2 和 Datetime:

SELECT SQL_NO_CACHE measured_on
FROM
    vertabelo.datetimemeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小18744343
最大61687797
平均31276103
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.datetimemeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查询 2 和 Timestamp:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.timestampmeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小26885953
最大666613531
平均36538412
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.timestampmeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查询 2 和 INT:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小20515844
最大700710469
平均34868088
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0" --host=localhost --user=root --concurrency=8 --iterations=25  --no-drop --create-schema=vertabelo

测试 2 总结

平均响应时间 (ms)Sysbench相对于 Datetime 的速度mysqlslap相对于 Datetime 的速度
Datetime3127-6103-
Timestamp3653慢 17%8412慢 38%
INT3486慢 11%8088慢 32%

再次,在两个基准测试工具中 Datetime 比 Timestamp 和 INT 快。但在这个测试中,INT 查询 —— 即使它使用了一个函数以转换日期 —— 比 Timestamp 查询更快得到结果。

测试 3:选择星期一产生的记录总数

这个查询返回一行,包含产生于星期一的所有记录的总数(从总共 1,497,421 行可用记录中)。

查询 3 和 Datetime:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.datetimemeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小17204063
最大45947812
平均27975540
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.datetimemeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查询 3 和 Timestamp:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.timestampmeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小19074578
最大543710235
平均34087102
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.timestampmeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查询 3 和 INT:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.inttimestampmeasures m
WHERE
    WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0; # MONDAY

性能

响应时间 (ms)Sysbenchmysqlslap
最小21085609
最大47649735
平均33077416
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.inttimestampmeasures m WHERE WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0" --host=localhost --user=root --concurrency=8 --iterations=25  --no-drop --create-schema=vertabelo

测试 3 总结

平均响应时间 (ms)Sysbench相对于 Datetime 的速度mysqlslap相对于 Datetime 的速度
Datetime2797-5540-
Timestamp3408慢 22%7102慢 28%
INT3307慢 18%7416慢 33%

再一次,两个基准测试工具都显示 Datetime 比 Timestamp 和 INT 快。不能判断 INT 是否比 Timestamp 快,因为 mysqlslap 显示 INT 比 Timestamp 略快而 Sysbench 却相反。

注意: 所有测试都是在一台 Windows 10 机器上本地运行的,这台机器拥有一个双核 i7 CPU,16GB 内存,运行 MariaDB v10.1.9,使用 innoDB 引擎。

结论

基于这些数据,我确信 Datetime 是大多数场景下的最佳选择。原因是:

  • 更快(根据我们的三个基准测试)。
  • 无需任何转换即是人类可读的。
  • 不会因为时区变换产生问题。
  • 只比它的对手们多用 1 字节
  • 支持更大的日期范围(从 1000 年到 9999 年)

如果你只是存储 Unix 时间戳(并且在它的合法日期范围内),而且你真的不打算在它上面使用任何基于日期的查询,我觉得使用 INT 是可以的。我们已经看到,它执行简单数值比较查询时非常快,因为只是在处理简单的数字。

Timestamp 怎么样呢?如果 Datetime 相对于 Timestamp 的优势不适用于你特殊的场景,你最好使用时间戳。阅读这篇文章后,你对三种类型间的区别应该有了更好的理解,可以根据你的需要做出最佳的选择。


via: http://www.vertabelo.com/blog/technical-articles/what-datatype-should-you-use-to-represent-time-in-mysql-we-compare-datetime-timestamp-and-int

作者:Francisco Claria 译者:bianjp 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

操作系统上的时间也许只是当做一个时钟。特别在控制台下, 我们通常并不认为时间有什么重要的。但是对于管理员,这种认识是错误的。你知道错误的日期和时间会导致你不能编译程序么?

因为日期和时间很重要,这或许就是开发网络时间协议(NTP:Network Time Protocol)的原因。让我们了解下date命令是如何工作的。

显示系统日期

要显示系统日期,只要输入:

$ date
Thu Dec 5 22:55:41 WIB 2013

格式化显示日期

日期有很多格式。如果你不喜欢默认的格式,你可以换一种格式。你可能会想"为什么我需要改变格式? 默认的输出对我足够了。"

是的,你说的对,但是当你在编程时,默认输出或许无法满足你的需求,因此需要一些自定义输出。

RFC 2822 的日期与时间输出格式

$ date -R
Thu, 05 Dec 2013 23:40:53 +0700

RFC 2822 的格式像这样 : 星期, 日-月-年, 小时:分钟:秒 时区

时区 +0700 等同于 GMT +7。

默认上date使用的是定义在/etc/localtime的时区。有效时区数据定义在/usr/share/timezones

显示或者设置协调世界时

Wikipedia上, UTC 意思是

世界上主要的时钟和时间的标准。这是格林位置标准时间几个非常相近的替代者之一。

以UTC形式显示日期和时间, 使用 -u 参数

$ date -u
Thu Dec 5 16:45:58:UTC 2013

使用格式化选项

要自定义你的日期格式, 使用加号 (+)

$ date +”Day : %d Month : %m Year : %Y”
Day: 05 Month: 12 Year: 2013
$ date +%D
12/05/13

%D 格式是 年/月/日 的格式.

如果你想的话,你可以输出日期的名字。下面是一些例子:

$ date +”%a %b %d %y”
Fri 06 Dec 2013

$ date +”%A %B %d %Y”
Friday December 06 2013

$ date +”%A %B %d %Y %T”
Friday December 06 2013 00:30:37

$ date +”%A %B-%d-%Y %c”
Friday December-06-2013 12:30:37 AM WIB

还有很多的日期格式。只要输入:

$ date –help

或者

$ man date

来显示date命令的语法和参数。

基本上,date命令会翻译所有所有的百分号(%)开头的格式和输出在引号("")内所有的内容。

设置系统日期和时间

通常地,你希望你的系统日期和时间是自动设置的。如果由于一些原因,你想要手动修改它,我们可以使用这个命令。

# date –set=”20140125 09:17:00”

这会设置你当前的系统日期和时间到一月 25, 2014 and 09:17:00 AM。请注意,你必须拥有root特权来这么做。不然你会得到这样一个错误。

date: cannot set date: Operation not permitted
Sat Jan 25 09:17:00 WIB 2014

重置你的时间

如果你希望重置你的系统日期和时间到原始值,你可以用这个技巧。

# hwclock
Fri 06 Dec 2013 03:44:10 AM WIB -0.314082 seconds

这回设置你的系统日期和时间到hwclock命令的输出的样子。

在脚本中使用date命令

还记得我之前说为什么你需要改变date的输出么?一个答案是你或许需要编程。让我们看下bash脚本下的一个例子。

$ vi display.date

#! /bin/bash
DATETIME=$(date +”DATE: %a %b-%d-%Y TIME: %T WEEK NUMBER: %W”)
echo $DATETIME

保存并运行它:

$ ./display.date
DATE : Fri Dec-06-2013 TIME: 03:08:19 WEEK Number :40

如果你发现权限拒绝错误信息,输入:

$ chmod 755 display.date

在备份流程中使用date

另外一个例子是子你备份流程中使用date。

$ date +%F
2013-12-06

$ tar zcfv /daily_backup/backup-`date +%F`.tar.gz /home/pungki/Documents

它会压缩文件夹/home/pungki/Documents到一个位于/daily\_backup folder的文件backup-2013-12-06.tar.gz中。(译注:通过“ 命令 ”来在命令行内嵌其它命令,这个字符不是单引号,而是和波浪号~同一个键位的那个符号。)

总结

date可能被认为在某些方面不重要。但是date扮演了一个重要的角色。要想知道关于date命令更多的细节,在你的控制台下输入man date访问man页面。


via: http://linoxide.com/linux-command/date-command-linux/

译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出