Python时间处理模块的常用选择:八大模块

时间数据

时间格式是数据类型中基础也不容忽视的一类。不像整数那样大道至简也不像字符串那样包罗万象,却独有魅力,时间数据本身除了加减、比较运算外,也有下周、去年、时区等更专项的时间切换。在各类编程语言里都提供时间对象的支持,在MySQL里也有DATETIME类型。商业里的DAU、GMV、LTV也少不了时间限定和时间属性,因此数据分析时少不了对时间数据类型的处理与转换。
Python通过套件time、datetime、timeit处理时间类型数据,但面对一些情况时会不够灵活和易用,在时间序列生成和截断方面捉襟见肘,于是诞生了Arrow、Pendulum、Maya等库增强了Python的时间处理能力。本篇对4个标准库和6大第三方模块进行介绍,在面对需求时能拿到最趁手的工具。

本文所用库概览

模块概览

在Python中进行时间类型数据处理能用到的模块有:

  • time:Python内置时间库,通过时间戳或元组表示时间;
  • datetime:内置日期库,处理日期时间对象和属性;
  • dateutil:基于datetime库的实用拓展,增强了对时间间隔和时间序列的处理;
  • pd.Timestamp:pandas库用于时间处理的类;
  • Arrow:优秀的Python时间库,简化了时间类型数据的解析和输出;
  • Pendulum:可以和Arrow对标的时间处理库,pendulum意为钟摆;
  • Delorean:在dateutil基础上进一步拓展的时间库,以《回到未来》中的时间旅行车命名;
  • moment:灵感来源于Moment.js,目前相对原始;
  • Maya:和Arrow等库对标,增强了对时区的处理,有调用pendulum的部分功能;

在深入这些库的使用之前,先补充一些先验知识:
epoch:时间基准点至特定时间的总秒数,一般用一个浮点数值记录,这个基准点在Unix及类Unix系统中是格林威治时间1970年01月01日00时0分0秒,因此也称为Unix时间戳(Timestamp)。因为地球是一个椭球体,当英国是中午时中国北京已经在吃晚饭了,不同经度地区的0点相对于格林威治的0点有一个时差,也就有时区(timezone)的区分,以UTC(世界协调时)作为基准,中国采用的东八区就可表示为UTC+8,对应北京时间减8个小时就是UTC时间。
基于以上需要考虑的问题,在时间类中,表示一个时间有两种基本选择:
一是用浮点数记录一个时间戳epoch,时间小于1970年则是负数,二是用元组或字典记录年月日时分秒时区等,在Python的time模块就是记录了epoch和一个元组叫struct_time,这两者之间可以互相转换。

模块特性与实践

time&datetime

time是Python内置的时间库,功能简约但实用,通常和同为内置库的datetime、pytz及calendar互相配合解决各类时间表示、计算、输出等需求。
time的常用方法有:

  • time.time():得到当前时间戳Timestamp,是一个浮点数;
  • time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准,相当于获取当前时间now();
  • time.gmtime(ts):时间戳转struct_time;struct_time是一个包含了9个元素的元组,对应着改时间对象的年月日、本年第几天等属性;
  • time.mktime(t):struct_time转时间戳;
  • time.strftime("%Y-%m-%d",t):struct_time转格式化字符串;
  • time.strptime('2020-12-7',"%Y-%m-%d"):字符串转struct_time;
import time
time.time() #type(time.time())==float
#Out[]:1607319973.764
time.localtime()
# time.struct_time(tm_year=2020, tm_mon=12, tm_mday=7, tm_hour=13, tm_min=46, tm_sec=13, tm_wday=0, tm_yday=342, tm_isdst=0)
st=time.gmtime(time.time())
st.tm_year #获取属性,st是元组,不能修改
# 2020

基于time模块生成的时间对象t,如果是时间戳形式表示的,是不能直接得到t是在哪一年等属性的,需要先转struct_time形式,然后就可以写st.tm_year获取所在年。st是元组,不能修改,即不能用st.tm_year=2019来修改的st的实际值。

t=time.strptime('2020-12-7 13:52:15',"%Y-%m-%d %H:%M:%S")
# time.struct_time(tm_year=2020, tm_mon=12,...)
time.strftime("%Y-%m-%d %H:%M:%S",t)
# 2020-12-7 13:52:15

从文件中读取数据时常需要从字符串形式变成时间对象,就会用到strptime,是string parse time的简写,即从字符串数据类型中解析成时间类型。strftime是把时间类型格式化为字符串,是strptime的逆操作,f是format的缩写。
时间类型格式化有一套特定的占位符,下面介绍的符号在其他时间模块里也通用,因此常用的占位符还是需要心里有数才能灵活“组装”出自己需要的字符串效果的。下面表格列出了常用的时间格式化占位符,更全面的表可查阅time模块文档

常用时间格式化符号

time模块常和datetime模块组合使用,time侧重在时间,datetime在日期方面方法更丰富,且datetime会和pytz及calendar配合处理时间对象。
在datetime里也有strftime和strptime,不过需要注意的是,两个库输入参数顺序的区别,datetime的strftime,格式化字符串在后,代码实例如下。

from datetime import datetime
dt=datetime.strptime('2020-12-7 13:52:15',"%Y-%m-%d %H:%M:%S")
datetime.strftime(dt,"%Y-%m-%d %H:%M:%S") #
# 2020-12-7 13:52:15
time.strftime("%Y-%m-%d %H:%M:%S",t)
# datetime库内部也是调用time的striptime
# datetime.strftime -> _wrap_strftime ->_time.strftime

在datetime中新建时间对象可以直接使用datetime(y, m,d,tzinfo)输入参数,用datetime.now()获得当前时间,通过datetime.fromtimestamp(ts)可以将时间戳ts转为时间对象,生成的datetime时间对象在获取属性时用到的语句类似dt.year,有year/month/day/hour/second/tzinfo等可以用。tzinfo是时区属性,datetime在时区相关处理时通常用到pytz。

import pytz
sh=pytz.timezone('Asia/Shanghai') #新建一个时区
dt=datetime(2020,12,7,hour=8,tzinfo=sh)
datetime.fromtimestamp(time.time())
#datetime.datetime(2020,12,8,16,59,42,797401)
dt.year #返回给定datetime对象的年份
#Out[]: 2020
#属性有.hour .minute .second .microsecond 等
datetime.weekday() #返回星期几,星期一为 0,星期天为 6
#方法还有 .isoweekday() .toordinal() 等
datetime.combine(dt.date(),dt.time()) 
#combine:将一个date对象和一个time对象组合成一个datetime对象
from datetime import timezone #如果不使用pytz库
d1=datetime(2020, 11, 21,tzinfo=timezone(timedelta(hours=8)))
tdt=dt-d1
# datetime.timedelta(days=16)
dt+timedelta(20)

两个datetime日期相减得到的是一个时间间隔对象(imedelta),timedelta可以和数值进行乘法和整除运算,两个timedelta对象之间可以进行加减运算,但不能比较大小,datetime对象可以和timedelta对象进行加减得到新的datetime实现时间偏移。
datetime也会和内置的calendar库进行配合,顾名思义,calendar库主要用来处理和输出整年、整月的日历。

print(calendar.calendar(2020)) #打印2020年日历
#calendar.prcal(2020) #两个语句效果相同
calendar.prmonth(2019,2) #打印2019年2月的日历
calendar.isleap(2020) #是否闰年
# True
calendar.weekday(2020,11,20) #指定日期为星期几,
#4 代表星期五


calendar

这几个库其他的实用方法有:

  • time.sleep(secs):线程推迟指定的时间运行,单位为秒;
  • time.asctime([t]) :把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993',如没有参数,将会将time.localtime()作为参数传入;
  • time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs));
  • calendar.leapdays(n,m):年份n到m之间的闰年数量;

dateutil

dateutil模块是基于datetime库的实用拓展,增强了对时间间隔和时间序列的处理,因此dateutil类型直接继承了datetime类型,dateutil库生成的时间对象就是datetime。Anaconda下该库已经安装,模块里有parser、easter、relativedelta、rrule等实用类进行时间处理。

import dateutil #anaconda下已经安装,直接import
dt=dateutil.parser.parse('April 29 2020 14:20')
#可以从字符串解析,不需要手动写匹配的占位符。
dt=dateutil.parser.parse('April 29') #会取当前年
# datetime.datetime(2020, 4, 29, 0, 0)
dt=dateutil.parser.parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)

dateutil的parser类用于更方便地从字符串解析为datetime对象,parser.parse(string)可以从各种类型的字符串例如一句自然语言中解析出日期,但输入的参数string必须是字符串,输入时间戳不行(这个和下面提到的Arrow等库不同)。
因为解析为datetime类型的对象,所以可以使用datetime的各种方法和属性,例如需要知道是哪一年仍然使用dt.year获取。
一些datetime类的方法可以基于dt实例使用,要实现从时间戳转时间对象,就可以使用dt.fromtimestamp(ts),获取当前时间,就可以使用dt.now()

dt.fromtimestamp(dt.timestamp()) #时间戳与时间对象互转
dt.strftime('%Y-%m-%d') #只能输入一个参数
#时间对象转字符串
dateutil.easter.easter(2020,method=3) 
#计算输入年份复活节的日期

dateutil计算时间间隔的方法封装在relativedelta里,通过输入参数months等明确间隔的时间距离,tz用于处理时区。

dt+dateutil.relativedelta.relativedelta(months=1, weeks=1)
#时间偏移
# datetime.datetime(2021, 1, 14, 14, 15, 39, 173204)
relativedelta(datetime(2003, 10, 24, 10, 0),dt) #得到一个时间间隔
relativedelta(NOW, johnbirthday) #得到一个人的年龄
#下周五对应的时间
dt+relativedelta(weekday=FR)

rrule类用于生成和处理一个时间序列。rrule的主要参数有:

  • freq:声明序列重复的周期;
  • count:生成多少个时间对象;
  • dtstart:开始的时间点;
list(dateutil.rrule.rrule(freq=dateutil.rrule.MONTHLY, count=4, dtstart=datetime(2020, 12,7)))
# [datetime.datetime(2020, 12, 7, 0, 0),datetime.datetime(2021, 1, 7, 0, 0),...]
list(dateutil.rrule.rrulestr("""
    DTSTART:20201207T090000
    RRULE:FREQ=DAILY;INTERVAL=10;COUNT=4
    """))
#效果同上,rrulestr是根据字符串规则生成时间序列

以上例子生成的是一个由4个时间对象组成的序列,开始时间是2020年12月7号,每月重复一条记录。rrule.rrulestr()是把字符串输入当参数。

pandas

实际在进行数据分析时,通常都会用到pandas库却不一定会导入datetime等库,而pandas模块也提供了Timestamp、Timedelta等类用于时间类型数据的处理转换。直接使用pd.Timestamp也更容易进行广播运算。

pandas的Timestamp对象用法和datetime库基本一致,各种dt.year属性都有,也有dt.isleapyear用于判断是否是闰年。pd.Timedelta对应datetime的timedelta,表示时间间隔。

df['时间']=pd.to_datetime(df['dt']) 
df['years']=df['时间'].apply(lambda x:x.year)
sdf=df.loc[df['years']==2018]
ddr=dd/(pd.Timestamp('2018-12-31')-pd.Timestamp('2018-1-1')).days 
df['tfs']=df['时间'].apply(lambda x:x.hour+x.minute/60+x.second/3600)

用pandas处理时间格式数据》讲述了一个处理Excel文件中时间数据的案例。

Arrow

Arrow是一个优秀的Python时间处理库,现在其他有追求的第三方时间处理库都喜欢在文档里对标Arrow,足矣见Arrow的影响力。Arrow通过收束接口增强了其易用性,可以快速上手使用,get统筹各种输入的解析,replace负责各种时间要素的修改,format解决各类格式化输出的需求,range处理时间序列生成问题。
Arrow解析字符串或datetime对象得到的是一个自定义时间对象,通过dt.time、dt.datetime、dt.timestamp等将时间数据从Arrow内置对象转为time等库的时间对象,一些例子如下。

import arrow #在Anaconda下已经安装
arrow.get('2020-12-08 17:31:20') 
#Out[]: <Arrow [2020-12-08T17:31:20+00:00]>
dt=arrow.get(1607334506) #get可输入Unix时间戳,也可输入datetime对象
dt.datetime #转为dateime类型
dt.naive #转为当地时区的datetime类型
dt.floor('hour') #从小时处截断,小时之后的数清零
d1.replace(hour=3)
d1.shift(weeks=+4) #当前时间4周后
d1.to('Asia/Shanghai') #换时区
dt.format('YYYY-MM-DD') #输出格式化字符串
arrow.Arrow.range('hour',arrow.now(),arrow.now().shift(hours=5))
#arrow生成时间序列
dt.humanize() #dt的自然语言表示

Arrow的具体用法可参考前文《Python处理时间数据的另一种选择,在标准库之外》。

arrow库用法概览

Pendulum

Pendulum也是一款很优秀的Python时间处理模块,其内置数据类型拓展自datetime,与datetime有着很好的兼容性。Pendulum比dateutil功能更丰富,足矣和Arrow对标。Arrow的易用性体现在接口简洁,Pendulum的易用性表现在很多datetime的方法都兼容,而且Pendulum的文档页面也更美观漂亮。Pendulum[ˈpendʒələm]意为钟摆,是很好的时间意向。Pendulum通过其内置的DateTime对象实现和拓展datetime.datetime的功能,同时封装出Duration、Period及Timezones处理时间偏移、时区、时间序列。

import pendulum
dt=pendulum.now() #获取本地时区的当前时间
#DateTime(2020,12,8,18,0,8,697484,tzinfo=Timezone('Asia/Shanghai'))
pendulum.tomorrow() #明天的这个时候
dt.year # 2020
dt.week_of_year #dt所在周是本年第几周
dt.age #dt对应日期目前的年龄
dt.strftime('%Y-%m-%d')
d2=dt.set(year=2019) #把年份变成2019
dt.add(years=-1) #把时间变成1年前,注意是years不是year
period = pendulum.period(dt, dt.add(days=8))
list(period.range('days',2)) #时间序列

其他的一些实用方法如下:

  • pendulum.datetime(2020,5,7):输入年月日等生成DateTime,对应着datetime.datetime()的写法;
  • pendulum.today():获取当天时间, .tomorrow() .yesterday() 等可以用;
  • pendulum.local(args):获取当地时间的对象,可以输入年月日等;
  • pendulum.parse(text):从文本中解析出时间对象,有个类似的方法是pendulum.from_format(text,s);
  • pendulum.from_timestamp(ts):把时间戳ts转为时间对象;
  • dt.int_timestamp:把dt表示为整数的timestamp,对应的还有.float_timestamp;
  • pendulum.timezone("Europe/Paris"):生成一个时区对象;
  • d2.diff_for_humans(dt):将时间间隔按自然语言输出;

Pendulum的一些函数需要输入DateTime作为参数时,输入datetime对象也兼容,例如Period时期对象的start、end对象输入DateTime对象或datetime对象都可以,更详细的Pendulum特性可阅读《挑战Arrow,需要怎样的实力?Pendulum使用笔记》。

pendulum-xmind

Delorean

dateutil库在datetime库基础上进行拓展,Delorean站在dateutil的肩膀上进一步增强了时间处理能力,其接口更偏向面向对象的写法,时间戳使用epoch定义,其时间对象和datetime对象兼容性也很高,并且内置时间对象可以直接和datetime.timedelta进行运算。
Delorean是《回到未来》中的主角的时间旅行车,作为一个以epoch表示时间的程序库挺契合的。
Delorean抽象了多个接口用于解析和转换其他格式数据为时间对象,解析字符串用parse、处理时间戳用epoch、输入的是datetime对象直接用Delorean()。获取对象的年月日等属性,需转datetime再使用datetime的接口。

from delorean import Delorean
dt=Delorean() #获取当前时间,相当于now
dt=delorean.parse('2020/12/07')
dt.datetime.year #获取年份
dt.replace(hour=8) #改时间
dt.shift('US/Eastern') #改时区
dt - timedelta(hours=2) #两小时之前
list(delorean.stops(freq=delorean.DAILY,count=10))

Delorean修改时间要素是用replace,而改时区是使用的shift。除了用stops生成时间序列外,还有range_daily()、range_hourly()等快速方法生成每天或每小时的时间序列。Delorean和datetime的协作很方便,但接口不够简洁和成体系,获取属性还需要转为datetime,显得常用的功能却没有优先封装,与Arrow、Pendulum等库还有些差距,是一个值得了解的Python时间库,详细了解其用法可看前文《设定基准点去时间旅行|Delorean使用笔记》。

delorean-xmind

moment

和Arrow类似,moment也是灵感来自Moment.js库。moment是一个在发展中的库,基本功能不缺,但也不是很完善,其文档 建议优先考虑Arrow及Pendulum库。
moment将数据的输入封装在moment.date里,在解析能力上,比Arrow的get更进一步,例如get传入tomorrow或者2 weeks ago是会报错的,这是arrow的get还不支持的写法,但moment.date可以解析。

import moment
moment.date('2020-12-07 14:20:10')
#<Moment(2020-12-07T14:20:10)>
moment.date("2 weeks ago")
dt=moment.date("December 18, 2020")
moment.unix(1355875153626)
dt.year #获取dt所在年份

moment的时间对象也是自定义的对象,获取其属性使用dt.year的写法,和其他库一致,进行时间偏移用的add和subtract方法,同时也有replace的接口,而且写dt.replace(day=2)或者dt.replace(days=2)都没出问题。输出格式化的字符串使用format。通过dt.datetime转为dateime类型,而输出时间戳是用dt.epoch()方法。

dt=moment.now() #还有utcnow()可以用
dt.add(days=2) #.subtract()
dt.replace(day=5)
dt.replace(days=5)
dt.format('YYYY-MM-DD')
dt.datetime #转datetime对象

moment目前的接口还是偏少,生成一个时间序列目前还不能实现。
使用moment时,一个小问题是用pip install moment可能会安装不上,需要通过pip install moment --user 去安装。

Maya

Maya站在datetime、pendulum、snaptime等模块的肩膀上发展有一定特色的时间处理能力,Maya自定义对象MayaDT也是通过epoch定义时间,能很好地避免一些时区问题。
Maya的时间创建能力上排名前列,有丰富的接口用于从各种数据中解析出时间对象,when和parse可以从一些自然语言字符串中解析出时间要素,这方面和moment不遑多让,例如写maya.when('tomorrow').when('2 weeks ago')等;当然从time/datetime对象、时间戳转Maya对象也是没有压力。

import maya
maya.when('tomorrow') #明天的这个时候,直接从自然语言转MayaDT
maya.parse('2020-12-08T03:15') #字符串转maya时间对象
dt=maya.now() #获取当前时间
maya.MayaDT.from_datetime(datetime.now()) #datetime对象转MayaDT
maya.MayaDT.from_struct(time.gmtime()) 
maya.MayaDT(1606533154) #时间戳转Maya时间对象
dt.from_iso8601(text) #从符合ISO-8601标准的字符串中解析时间

在输出和转换方面,有dt.datetime()方法将MayaDT对象转为datetime对象,也能直接通过dt.year获取MayaDT对象的属性,有dt.iso8601()输出满足ISO-8601标准的时间字符串,和from_iso8601相对应。几个优秀库都有的输出为自然语言功能在Maya里封装为dt.slang_time(),并且还有slang_date也能使用,slang是俚语的意思。

dt=maya.when('2020, 12, 7')
dt.slang_time()
# '8 hours ago'
dt.add(days=10).slang_time()
# 'in 1 week'
list(maya.intervals(start=maya.now(),
                    end=maya.now().add(days=1),
                    interval=60*60))
#生成start到end的每小时间隔的时间值序列

Maya的很多方法调用了其他时间库,例如dt.year等属性用了datetime库、snap方法是调用了snaptime库、parse和add用到了Pendulum库,很多需求Maya没有自己去造轮子,同时也显得依赖项有些多,要深入了解Maya的用法可以翻看前文《博采众长穿梭时空|Maya库使用笔记》。

maya库概览

在程序运行方面,除了时间数据本身,量测代码运行时间、模拟特定时间环境,都是编程语言层的使用场景。在Python中,timeit库用于量测一段代码的运行时间,即可以方便地计算代码跑一次的耗时,也能计算多次重复运行的平均耗时,在进行代码评测时小巧实用。FreezeGun 是在进行测试时常用的时间库,主要应用场景是做测试时保证输入的一致性;功能是调用freeze_time后,程序运行返回的时间就是冻结所在的时间,相当于测试任务是在那个时间运行的。

from timeit import timeit
timeit('x=1')  #看执行1000000次x=1的时间
def func():
    s=[i for i in range(1000)]
    return s
timeit('func()', number=1) #执行函数func 一次的时间
from timeit import repeat
#repeat和timeit用法相似,多了一个repeat参数,表示重复测试的次数(可以不写,默认值为3.),返回值为一个时间的列表。
t = repeat('func()', 'from __main__ import func', number=100, repeat=5)
#在命令行中使用:
python -m timeit '"-".join(str(n) for n in range(100))'

from freezegun import freeze_time
@freeze_time("2012-01-14")
def test():
    return datetime.now()
test()
#FakeDatetime(2012, 1, 14, 0, 0)
freezegun的使用效果

总结

在数据处理和数据分析过程中,主要需要解决的数据需求有以下几点:

  • 生成时间对象,从字符串或者写赋值语句得到一个时间对象;从内置的time/datetime对象转更容易处理的时间对象,如数据列是从Excel读入的,去解析该列为时间对象;
  • 对特定时间对象t,获取年月日、分钟等时间要素;
  • 时间运算;
    • 时间间隔Timedelta,两个时间对象相减;
    • 一个时间对象+一个差值后得到新的时间对象,例如获取t一周后的时间t2,
  • 时间对象转为特定格式的字符串;
  • 时间序列的整体移动与抽样;
  • 非结构日期处理,从自然语言中解析时间;

各个库解决该需求的方式总结如下表。


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容