神奇的闹钟
题目
小蓝发现了一个神奇的闹钟,从纪元时间(19701970 年 11 月 11 日 00:00:0000:00:00)开始,每经过 xx 分钟,这个闹钟便会触发一次闹铃 (纪元时间也会响铃)。这引起了小蓝的兴趣,他想要好好研究下这个闹钟。
对于给出的任意一个格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss 的时间,小蓝想要知道在这个时间点之前 (包含这个时间点) 的最近的一次闹铃时间是哪个时间?
注意,你不必考虑时区问题。
输入格式
输入的第一行包含一个整数 TT,表示每次输入包含 TT 组数据。
接下来依次描述 TT 组数据。
每组数据一行,包含一个时间(格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss)和一个整数 xx,其中 xx 表示闹铃时间间隔(单位为分钟)。
输出格式
输出 TT 行,每行包含一个时间(格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss),依次表示每组数据的答案。
样例输入
2 2016-09-07 18:24:33 10 2037-01-05 01:40:43 30
样例输出
(3)
学习助手
问题描述
小蓝发现了一个神奇的闹钟,从纪元时间(19701970 年 11 月 11 日 00:00:0000:00:00)开始,每经过 xx 分钟,这个闹钟便会触发一次闹铃 (纪元时间也会响铃)。这引起了小蓝的兴趣,他想要好好研究下这个闹钟。
对于给出的任意一个格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss 的时间,小蓝想要知道在这个时间点之前 (包含这个时间点) 的最近的一次闹铃时间是哪个时间?
注意,你不必考虑时区问题。
输入格式
输入的第一行包含一个整数 TT,表示每次输入包含 TT 组数据。
接下来依次描述 TT 组数据。
每组数据一行,包含一个时间(格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss)和一个整数 xx,其中 xx 表示闹铃时间间隔(单位为分钟)。
输出格式
输出 TT 行,每行包含一个时间(格式为 уууу-MM-ddHH:mm:ssуууу-MM-ddHH:mm:ss),依次表示每组数据的答案。
样例输入
2 2016-09-07 18:24:33 10 2037-01-05 01:40:43 30
样例输出
2016-09-07 18:20:00 2037-01-05 01:30:00
思路
一个很容易想到的思路是直接获取该时间的时间戳,因为刚好该该事件起始时间为时间戳0,然后直接将时间戳对空格时间取模得到结果,最后直接将结果减去取模的值得到最终结果。但是有个重要点–时区。该问题没处理好会出问题
下面是错误代码(因为时区问题)
import sys
import datetime
import time
lens=int(sys.stdin.readline())
data=[]
pattern="%Y-%m-%d %H:%M:%S"
for i in range(lens):
times,a,space=sys.stdin.readline().split()
times=times+' '+a
times=datetime.datetime.strptime(times,pattern)
times=times.timestamp()
spaces=times%(int(space)*60)
print(datetime.datetime.fromtimestamp(times-spaces).strftime(pattern))
上述代码中主要问题是:时区,具体来说就是输timestamp()转化得到的时间戳是根据系统时间得到的,然后对该时间戳进行计算。最后在使用datetime变为格式时间,这里会导致时间问题出现问题。解决方法是在每次将datetime变为时间戳和将时间戳变为datetime的时候先设置为UTC时区。修改方法如下
# times:需要修改的datetime对象
times=times.replace(tzinfo=datetime.timezone.utc)
总的来说,这个思路没有问题,但是问题出在时区,因此为了避免这个问题解决方法是:避免时间戳和datetime对象之间的转化,或者直接设置时区后进行转化。
设置时区
import sys
import datetime
def main():
lens = int(sys.stdin.readline())
pattern = "%Y-%m-%d %H:%M:%S"
for _ in range(lens):
line = sys.stdin.readline().strip()
# 分割时间部分和x
parts = line.split()
# 合并时间部分,格式为 "yyyy-MM-dd HH:mm:ss"
time_str = ' '.join(parts[:2])
x = int(parts[2])
# 解析时间字符串为datetime对象
dt = datetime.datetime.strptime(time_str, pattern)
# 设置为UTC时区
dt_utc = dt.replace(tzinfo=datetime.timezone.utc)
timestamp = dt_utc.timestamp()
# 计算余数
interval = x * 60
remainder = timestamp % interval
# 最近的响铃时间
nearest_timestamp = timestamp - remainder
# 转换为datetime对象并格式化输出
nearest_dt = datetime.datetime.fromtimestamp(nearest_timestamp, tz=datetime.timezone.utc)
# 注意要转换为naive datetime以符合示例输出的格式要求(假设示例输出是UTC时间)
# 使用.replace(tzinfo=None)去掉时区信息,但确保时间正确
nearest_naive = nearest_dt.replace(tzinfo=None)
print(nearest_naive.strftime(pattern))
if __name__ == "__main__":
main()
避免对象转化
datetime.timedelta
是专门设置的时间间隔对象。该对象可以方便的操作。构造方法如下:
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
这些参数都是可选对象,这里只需要设置minutes为时间间隔即可。最终代码如下:
import sys
import datetime
lens=int(sys.stdin.readline())
data=[]
pattern="%Y-%m-%d %H:%M:%S"
start=datetime.datetime(1970,1,1,0,0,0)
for i in range(lens):
times,a,space=sys.stdin.readline().split()
times=times+' '+a
times=datetime.datetime.strptime(times,pattern)
time_delta=datetime.timedelta(minutes=int(space))
time_new=times-(times-start)%time_delta
print(time_new.strftime(pattern))