自我研究:记录自己每天的睡眠

在 2023 年底的时候,我开始准备记录自己每天的时间是怎么安排的。

其实对于我自己来说,最大的驱动力来自记录自己的睡眠。毕竟作为「研究生」,平时也没有白天一定要做什么事情的需求(除了开会),生物钟经常颠倒,睡觉也睡的不好。如果能够自己统计一些具体的数据,或许可以分析分析怎么才能让自己的生物钟正常点,每天睡的时间也能多一点。

其实当时我也调研了一些可能的 app 去做时间记录,但是我自己可能是一个比较挑剔的人,根据我的以下需求,确实是很难有满足我要求的第三方工具了:

能导出 CSV 数据:别人画的图毕竟受限,想好看我有了数据可以自己 Python 画足够方便:随时随地记录,而且点击要少,时间要短(一定一定不能有诸如开屏广告的玩意儿)可自由定制类型:我可以只把时间分成两类(生活+工作),也可以细分到每一个工作项目,每一种生活类型(甚至玩哪个游戏),选择哪种方案是我的自由,想简单可简单,想复杂可复杂好吧,说到这儿,我说实话已经不太可能找别人开发的方案了。

基于快捷指令的时间记录「app」聊几句我自己的背景:我是做生信的,代码能力不强,也就玩玩 Python 的水平,写 iOS app 是绝对不行的。不过本段涉及的算法技术只有 if-else,其他部分大家真的随便看看就懂了。

既然都想自己搞了,我就把目光投向了 iOS 上的快捷指令。

在讲快捷指令之前,我甚至还尝试过一个更离谱的做法,写一段 Python 程序,然后手机执行代码,把记录结果远程发送到电脑。(这听着也太麻烦了吧)

一阵摸索后,我发现快捷指令比我想象中好用太多,其实本质上就是傻瓜式编程的软件,或者可以理解成现在流行的「无代码编程」。而且作为颜值控,快捷指令居然能生成一个类似于 app 的图标放在主屏,甚至这个图标还可以用自己的图片!能拥有自己定制的 logo 真是太美好了。

那么到这里,我们已经准备好了实现的途径,现在来列一下实际的需求:

能导出 CSV 数据:app 的输出存放在便签中,作为纯文本数据,其实已经很容易读取;足够方便:每次记录时间点击屏幕三次(包括打开 app),不能再多了;可自由定制类型:方便地添加/删除记录的类型。于是我的流程便是:

手动打开 app ➡️ 手动选择大类 (Work/Life) ➡️ 手动选择小类 (Relax/Gaming/Sleep/Travel) ➡️ 自动生成一段文字 ➡️ 自动添加到某个便签的最后一行

第一步:选择大类第二步:工作大类中选择小类第二步:生活大类中选择小类最后一步:把结果(一句话)添加到便签实际操作:点两下就行上图就是实际操作的界面,两次点击(算上打开 app 三次)就可以了,真的很方便。而且我还换了一个好看的 logo,这样我就更有动力去点它了

输出的便签长这样:

Major: [Life]. Minor: [Life: Relax]. Starting at: [Jul 26, 2024 at 05:38]

Major: [Life]. Minor: [Life: Sleep]. Starting at: [Jul 26, 2024 at 08:01]

Major: [Life]. Minor: [Life: Relax]. Starting at: [Jul 26, 2024 at 12:00]

Major: [Life]. Minor: [Life: Relax]. Starting at: [Jul 27, 2024 at 12:04]养成习惯还是需要一些过程的,平时的我需要睡觉前点一下,起床点一下,开始干活点一下,准备吃饭点一下,说白了还是小有点麻烦。所以我一开始分的类多,后面其实分类就越来越少了,无非就分休息/睡觉/工作这几个了。

统计结果可视化既然都有了统计的结果,我们就可以根据记录的时间来做图了。我最近还是比较关心我每天睡的好不好,特别是每天到底睡够了没。

于是我就写了一段 Python 画图的代码,看看从今年第一天到现在(八月)每天睡了几个小时:

钟二每天睡了几个小时?哎,上两周睡的也太惨了😭

如果统计一个直方图的话:

钟二睡觉时长居然符合正态分布?群友锐评 1:睡眠时间能拉出以小时为单位的正态有点狠啊

群友锐评 2:感觉我要是用钟老师的 colorbar,这一张热图都是蓝的

不过我自己感觉还算良好,居然我大半部分时间都有错过六小时睡眠,我已经很满足了。

后话我自己算是一个比较爱折腾的人,能为了记录个时间折腾半天也是没谁了 hhh。

其实除了看睡了几个小时,我之前还统计过我自己做的每个项目到底花了多少时间。等最后有了回报之后,我就能统计下我的时间/产出比了。还有一段时间我总觉得我的人生浪费在了无穷无尽无聊的开会中,我当时也统计了下我一周到底花了多少时间在开会上(真的很多!),那次之后我就开始翘会了,能不开就别开了

这个 TimeTracker 已经变成我生活中有趣的一部分了,今天分享给大家,要是感兴趣的话也欢迎大家来交流和尝试

Source code画图的代码就不公开了,大家多多培养自己的艺术细胞吧

读便签数据:

# load timetracker data

# the line format: Major: [MAJOR_TYPE]. Minor: [MINOR_TYPE]. Starting at: [MONTH DAY, YEAR at TIME]

def load_timetracker_records(file_path):

"""Load timetracker records from a file

Args:

file_path (str): The path to the file

Returns:

pd.DataFrame: A DataFrame containing the records

- major: The major activity

- minor: The minor activity

- start_time: The starting time

- end_time: The ending time

"""

major_activities = []

minor_activities = []

start_times = []

with open('timetracker.txt', 'r') as f:

# skip first line (first line is "time tracker")

f.readline()

for line in f:

major, minor, start_time = re.findall(r"\[([^\]]+)\]", line)

start_time = datetime.strptime(start_time, "%b %d, %Y at %H:%M")

# add to lists

major_activities.append(major)

minor_activities.append(minor)

start_times.append(start_time)

end_times = start_times[1:] + ["None"]

return pd.DataFrame({

'major': major_activities,

'minor': minor_activities,

'start_time': start_times,

'end_time': end_times

})

统计每天睡眠时长:

# create a blank calendar

# result: a list of day names, a list of start of day time, a list of end of day time

calendar_name_list = []

calendar_start_of_day_time_list = []

calendar_end_of_day_time_list = []

# generate calendar data

for i in range((time_end_date - time_start_date).days):

date = time_start_date + timedelta(days=i)

start_of_day = date.replace(hour=0, minute=0)

end_of_day = start_of_day + timedelta(days=1)

calendar_name_list.append(date.strftime("%b %d, %Y"))

calendar_start_of_day_time_list.append(start_of_day)

calendar_end_of_day_time_list.append(end_of_day)

sleep_calendar = [0 for _ in range(len(calendar_name_list))] # sleep calendar record sleep time for each day

# enumerate through time tracker records

for i in range(len(data)):

record = data.iloc[i]

major = record['major']

minor = record['minor']

start_time = record['start_time']

end_time = record['end_time']

# if the record is a sleep record

if major == "Life" and minor == "Life: Sleep":

# find the corresponding day

for j in range(len(calendar_name_list)):

if start_time >= calendar_start_of_day_time_list[j] and start_time < calendar_end_of_day_time_list[j]:

if end_time >= calendar_start_of_day_time_list[j] and end_time < calendar_end_of_day_time_list[j]: # if the sleep record is within the same day

duration = end_time - start_time

duration_hours = duration.total_seconds() / 3600

sleep_calendar[j] += duration_hours

elif end_time >= calendar_end_of_day_time_list[j]: # if the sleep record spans multiple days

duration_today = calendar_end_of_day_time_list[j] - start_time

duration_today_hours = duration_today.total_seconds() / 3600

sleep_calendar[j] += duration_hours

remaining_duration = end_time - calendar_end_of_day_time_list[j]

remaining_duration_hours = remaining_duration.total_seconds() / 3600

for k in range(j+1, len(calendar_name_list)):

if remaining_duration_hours > 0:

if remaining_duration >= timedelta(days=1):

sleep_calendar[k] += 24

remaining_duration -= timedelta(days=1)

remaining_duration_hours = remaining_duration.total_seconds() / 3600

else:

sleep_calendar[k] += remaining_duration_hours

remaining_duration_hours = 0

else:

break

else:

raise Exception("Invalid sleep record: " + str(record))

sleep_calendar = np.array(sleep_calendar)

# append np.nan to be the 7*n

n = 7

if len(sleep_calendar) % n != 0:

sleep_calendar_reshape = np.append(sleep_calendar, [np.nan for _ in range(n - len(sleep_calendar) % n)])

sleep_calendar_reshape = sleep_calendar_reshape.reshape(-1, n)

else:

sleep_calendar_reshape = sleep_calendar.reshape(-1, n)> 关注 少数派小红书,感受精彩数字生活 🍃

> 实用、好用的 正版软件,少数派为你呈现 🚀

[an error occurred while processing the directive]
Copyright © 2088 时代中心网 - 经典游戏活动回顾 All Rights Reserved.
友情链接