import time
时间戳又被称之为是Unix时间戳,原本是在Unix系统中的计时工具。
它的含义是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。UNIX时间戳的 0 按照ISO 8601规范为 :1970-01-01T00:00:00Z。
比如:
小知识:最开始的时候,时间戳的开始年份是1971年,那个时候Unix系统和C语言刚刚诞生,所以时间戳0也就是Unix系统和C语言的生日。那时候的时间位数只有32位,而且每秒中有60个数字,发现只要两年多的时间时间戳就能完成一个轮回,十分的不方便!所以后来的一系列改革,将时间戳的数值改为每秒1个数字,还有一些新的系统可以将时间戳的位数增大,可以让时间戳的轮回扩展到一百多年,再后来为了方便人们记忆,将时间戳的起始年份定位1970年整。
import time
stamp_time = time.time()
print(stamp_time) # 1635768368.2838552
参数为时间戳,默认为本地时间戳,获取时间元组。
时间元组是python中的一个特殊的数据类型type: time.struct_time,但是它和tuple的特性是相同的。
import time
# 时间元组中的值分别表示:
# tm_year: 年
# tm_mon: 月
# tm_mday: 日
# tm_hour: 时
# tm_min: 分
# tm_sec: 秒
# tm_wday: 周几(0表示星期一)
# tm_yday: 一年中的第几天(从1开始)
# tm_isdst: 夏令标识(1夏令时、0非夏令时、-1未知)
# 默认当前时间
time_tuple = time.localtime()
print(time_tuple)
# time.struct_time(tm_year=2021, tm_mon=11, tm_mday=1, tm_hour=20, tm_min=7, tm_sec=50, tm_wday=0, tm_yday=305, tm_isdst=0)
# 指定时间戳
time_tuple = time.localtime(3600)
print(time_tuple)
# time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=9, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
有大问题啦!!!
时间戳的起始时间是1970-1-1 0:0:0, 这个时候的时间戳是0,那么时间戳3600就是整整一个小时之后,那么时间就应该是1970-1-1 0:1:0 才对的呀!怎么上面的3600确实9点钟了呢?怎么起始时间变成了8点了呢?
然后你发现你在中国,时间是北京时间,北京在东八区时区,嘶,怎么正好也是个八?
是这样的,按照道理来说的话全世界任何一个地方的时间戳所代表的时间都应该是一样的,而且时间戳的起始时间确实是 1970-1-1 0:0:0 ,但是这个时间是位于英国的一个叫做格林威治的小镇的,格林威治有一个天文台叫做皇家格林尼治天文台,后来国际上将这个地方的经线作为本初子午线,作为时间计算时间和地理精度的起点。那么,有时区的存在打破了这个可能,我们在中国,所有的设备都是按照中国的时区编码的,中国位于东八区,在时间上比英国快八个小时,所以我们中国的本地时间戳就是 1970-1-1 8:00:00。
在不知道这个函数的时候,我就很好奇为什么localtime的初始时间比格林威治时间要快8小时,现在就明白了:
| 函数 | 描述 |
|---|---|
| gmtime | 获取时间元组(GMT格林威治时间) |
| localtime | 获取时间元组(UTC协调世界时) |
注意:
time.struct_time 或者元组 tuple 类型;import time
# 在中国的最小时间单位
tst = (1970, 1, 1, 8, 0, 0, 0, 0, 0)
time_stamp = time.mktime(tst)
print(time_stamp) # 0.0
参数默认为本地时间戳,获取的数据类型是 str,这个时间字符串不像时间元组是一个单独的数据类型。
import time
# 时间字符串中的含义是:
# Mon Nov 1 21:34:39 2021
# 星期 月 日 时 分 秒 年
# 默认为本地时间戳
time_char = time.ctime()
print(time_char) # Mon Nov 1 21:34:39 2021
# 指定时间戳
time_char = time.ctime(0)
print(time_char) # Thu Jan 1 08:00:00 1970
注意,asctime有弊端,看下例:
import time
tst = (1970, 1, 1, 8, 24, 61, 1, 0, 0)
time_char = time.asctime(tst)
print(time_char) # Tue Jan 1 08:24:61 1970
tst = (1970, 1, 1, 8, 24, 61, 2, 0, 0)
time_char = time.asctime(tst)
print(time_char) # Tue Jan 1 08:24:61 1970
看上面的例子,时间元组变成时间字符串的时候,会将星期的数据也读取到,但是却不会分辨数据是否正确,所以asctime并不常用。
如果要将一个不确定正确性的时间元组变成时间字符串的话,先通过 mktime 获取时间戳(mktime可以分辨出正确的时间信息),然后在将时间戳通过 ctime 变成时间字符串。
格式化时间,按照指定的格式(一段格式化字符串,就像字符串的格式化一样)将时间元组变成时间字符串。
我们先来学习一下时间占位符的含义是什么:
注意!!!这些占位符的大小写的含义是不同的:
| 占位符 | 含义 |
|---|---|
| %Y | 以十进制数字表示以世纪为单位的年份(四位数) |
| %y | 以十进制数字表示年份(两位数) |
| %m | 以十进制数字表示月份 |
| %D | 以月/日/年(两位数)的格式表示年月日 |
| %d | 以十进制数字表示日期 |
| %H | 以十进制数字表示二十四小时制的时 |
| %M | 以十进制数字表示分钟 |
| %S | 以十进制数字表示秒 |
| %z | 与UTC的时区偏移 |
| %a | 区域设置的缩写工作日名称 |
| %A | 区域设置的完整工作日名称 |
| %b | 区域设置的缩写月份名称 |
| %B | 区域设置的完整月份名称 |
| %c | 语言环境的适当日期和时间表示 |
| %I | 以十进制数表示十二小时制的时(大写 ‘爱’) |
| %p | 语言环境的等效值:AM 或者 PM |
现在根据使用时间占位符用字符串格式化将时间元组变成字符串。
import time
# 注意,如果格式化字符串中出现中文字符,只能在linux系统下运行,windows下不能解析,直接报错。
tst = (1970, 1, 1, 8, 0, 0, 0, 0, 0)
time_tuple = time.strftime('%Y-%m-%d-%H-%m-%S',tst)
print(time_tuple) # 1970-01-01-08-01-00
# 有中文在windows下报错
tst = (1970, 1, 1, 8, 0, 0, 0, 0, 0)
time_tuple = time.strftime('%Y-%m哈哈-%d-%H-%m-%S',tst)
print(time_tuple) # 1970-01-01-08-01-00
格式化时间,通过格式化字符串将一个字符串中的时间变成时间元组。
import time
# 格式化字符串要和原字符串一模一样,只是将需要提出的部分使用占位符替换
char = '2000年10月30日一个伟大的中国少年在三晋大地诞生了'
format_char = '%Y年%m月%d日一个伟大的中国少年在三晋大地诞生了'
tst = time.strptime(char, format_char)
print(tst)
等待指定秒数的时间:
import time
print('开始睡觉')
time.sleep(2)
print('睡了两秒钟,神清气爽')
用于计算程序运行的时间
import time
# perf_counter 用于计算程序运行的时间
# 记录开始时间
start_time = time.perf_counter()
# 程序运行
for i in range(10000):
pass
# 记录时间
end_time = time.perf_counter()
# windows系统直接拿到第二次的值就可以了,不用减去第一次的值也行
print(end_time, '秒') # 0.0003918 秒
print(end_time - start_time, '秒') # 0.0003916 秒
如果使用多次perf_counter()函数,直接输出其的值是距第一次使用的时间长度:
import time
time1 = time.perf_counter()
time.sleep(1)
time2 = time.perf_counter()
print(time2)
time.sleep(2)
time3 = time.perf_counter()
print(time3)
time.sleep(3)
time4 = time.perf_counter()
print(time4)
"""
结果:
1.0002558
3.0048941
6.019172
"""
注意:windows系统下使用perf_counter()函数可以直接输出耗时长度,每次的耗时默认都是距离第一次使用perf_counter()函数的时间长度;如果在linux系统下使用perf_counter()函数则必须要使用第二次的结果减去之前的结果,因为在linux系统中perf_counter()函数的值和time()函数的值都是一样的,那就是返回一个时间戳。
使用time.time()计算时间
import time
# perf_counter 用于计算程序运行的时间
# 记录开始时间
start_time = time.time()
# 程序运行
for i in range(10000):
pass
# 记录时间
end_time = time.time()
print(end_time - start_time, '秒') # 0.001001119613647461 秒
耗时短的计时推荐使用pref_counter,耗时长的推荐使用time。
# 1、定义进度条样式
print('[%-50s]' % ('###########'))
print('[%-50s]' % ('###################'))
print('[%-50s]' % ('###########################'))
print('[%-50s]' % ('####################################'))
print('[%-50s]' % ('########################################'))
# 2、让进度条动起来
import time
progress_char = ''
for i in range(50):
progress_char += '#'
time.sleep(0.05) # 延时看起来不是很快
# end使不能换行,\r使进度条不断刷新,保持在同一行显示;
print('\r[%-50s]' % (progress_char), end='')
print('\n')
# 3、根据文件的大小调整进度条的进度
import time
def progress(percent):
"""控制进度条的显示
参数是下载的百分比,用来控制进度条的进展
"""
# 如果百分比超过了1,说明数据已经接受完毕
if percent > 1:
percent = 1
# 打印对应的进度条效果
char = '#' * int(percent * 50)
print('\r[%-50s]%d%%' % (char, int(percent * 100)), end='')
# 已下的大小
rec_size = 0
# 下载文件的大小
total_size = 102400
# 模拟下载过程
while rec_size < total_size:
rec_size += 10240 # 下载速度
time.sleep(0.05) # 模拟网络延迟
percent = rec_size / total_size # 计算下载的进度(百分比)
# 调用进度条
progress(percent)
在学习了perf_counter计时后,我们知道有很多种方法可以用于计时:
import time
def loop():
time.sleep(1)
input('请输入:') # 这个位置人为数三秒回车执行
num = 10 ** 8
for _ in range(num):
pass
time.sleep(1)
# time.time
start_time = time.time()
loop()
end_time = time.time()
print(start_time) # 1640270620.4077902
print(end_time) # 1640270628.1165576
print(end_time - start_time) # 7.708767414093018
# time.perf_counter
start_time = time.perf_counter()
loop()
end_time = time.perf_counter()
print(start_time) # 3e-07
print(end_time) # 7.823952
print(end_time - start_time) # 7.8239517
# time.process_time
start_time = time.process_time()
loop()
end_time = time.process_time()
print(start_time) # 3.234375
print(end_time) # 4.8125
print(end_time - start_time) # 1.578125
除此之外,python3.7之后,新增了精确到纳秒的函数:
还有标准库timeit用于程序的性能计时。
在上述的几种类型中存在时间转换的问题,详情和之间的关系可以参考下图:

import datatime
datatime模块重新封装了time模块,提供更多的接口。
date类专门用于描述日期,实例化对象时必须填入参数,分别表示:年、月、日,返回datetime.date对象。
datetime.date(year, month, day)
from datetime import date
date_o = date(2022, 3, 1)
print(date_o)
print(type(date_o))
"""
结果:
2022-03-01
<class 'datetime.date'>
"""
| 属性 | 作用 |
|---|---|
| year | date对象表示的具体年份(实例化对象调用达到效果); |
| month | date对象表示的具体月份(实例化对象调用达到效果); |
| day | date对象表示的具体日(实例化对象调用达到效果); |
| max | date类能够表示的最大日期; |
| min | date类能够表示的最小日期; |
| resolution | date类能够表示的最小单位; |
注意,以下方法如果可以返回新的对象,使用对象调用时,返回新的对象,原对象不变;如果根据对象值返回对应的值,则使用类调用达不到目标效果;
| 方法 | 作用 |
|---|---|
| today() | 返回本地日期对象; |
| fromtimestamp(time_stamp) | 给定时间戳返回日期对象; |
| replace(y, m, d) | 给定年月日返回日期对象; |
| timetuple() | 返回本地当前时间元组time.struct_time对象; |
| weekday() | 返回星期序号,星期一返回0; |
| isoweekday() | 返回星期序号,星期一返回1; |
| isocalendar() | 返回元组,表示日期的年份、第几周、第几周之后的第几天; |
| isoformat() | 返回时间字符串; |
| strftime() | 格式化日期,参考time.strftime(); |
time类是datetime模块中专门用于描述时间的类,四个参数:hour、minute、second、microsecond默认都为0。
datetime.time(hour=0, minute=0, second=0, microsecond=0)
from datetime import time
time_0 = time()
print(time_0)
print(type(time_0))
"""
结果:
00:00:00
<class 'datetime.time'>
"""
time的属性和date类的属性方法基本相同,可以参考使用;
相同于date和time两个类的结合,使用基本相同;
timedelta类用于时间运算,类的参数有datetime模块支持的所有时间单位,使用其它的时间和日期对象可以和timedelta对象进行时间加减运算,注意在实例化时使用关键字传参;
from datetime import datetime
from datetime import timedelta
# 日期对象
datetime_o = datetime(2000, 10, 30, 14, 40, 6)
print(datetime_o)
# ## 假设我们要计算这个时间5天4小时23分6秒之后的时间
# 实例化 5天4小时23分6秒 的timedelta对象
timedelta_o = timedelta(days=5, hours=4, minutes=23, seconds=6)
# 将时间对象和timedelta对象相加
datetime_o += timedelta_o
print(datetime_o)
"""
结果:
2000-10-30 14:40:06
2000-11-04 19:03:12
"""
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我看到这个错误:translationmissing:da.datetime.distance_in_words.about_x_hours我的语言环境文件:http://pastie.org/2944890我的看法:我已将其添加到我的application.rb中:config.i18n.load_path+=Dir[Rails.root.join('my','locales','*.{rb,yml}').to_s]config.i18n.default_locale=:da如果我删除I18配置,帮助程序会处理英语。更新:我在config/enviorments/devolpment
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的