当前位置: 首页 > news >正文

从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案

在编程世界里,从 UTC 日期时间字符串获取 Unix 时间戳,看似简单,实则暗藏玄机。你以为输入一个像 “Fri, 17 Jan 2025 06:07:07” 这样的 UTC 时间,然后轻松得到 1737094027(从 1970 年 1 月 1 日 00:00:00 UTC 开始经过的秒数)就万事大吉了?事实可没这么简单,这背后涉及到一系列复杂的时间处理问题,还会让你发现 POSIX 时间处理函数在不同 C 库及相关语言中的各种 “意外特性”。今天,咱们就来深入探讨一下这个让人又爱又恨的话题。

一、时间处理的复杂性

时间本身就是一个复杂的概念,要是再把闰秒和相对论这些因素考虑进去,那就更让人头疼了。而人类对时间的记录方式,从模糊不清到精确无比,各不相同。就拿阿姆斯特丹的时间来说,由于夏令时的存在,“2025 年 3 月 30 日 02:20” 这个时间点在当地是不存在的,时间会直接从 01:59:59 跳到 03:00:00。但 “2024 年 10 月 27 日 02:30” 就更让人困惑了,因为夏令时结束时,02:59:59 的下一秒又回到了 02:00:00,这就导致有两个 “02:00” 的时间点。从下面的命令行示例就能看出工具在处理这种情况时的随意性:

$ TZ=Europe/Amsterdam date -d '20241027 01:59:59' +"%Y-%m-%d %H:%M:%S %s %z"
2024-10-27 01:59:59 1729987199 +0200
$ TZ=Europe/Amsterdam date -d '20241027 02:00:00' +"%Y-%m-%d %H:%M:%S %s %z"
2024-10-27 02:00:00 1729990800 +0100

你看,当要求解释 02:00:00 这个时间时,GNU date 工具选择了第二个出现的时间点。而且据我观察,这还和执行命令的时间有关,如果在四月执行,可能就会选择第一个 02:00:00 实例,是不是很让人摸不着头脑?

二、POSIX 时间概念与 struct tm

在 POSIX/Unix 系统中,指定时间的有效方式是用相对于某个 “纪元”(epoch)的秒数。POSIX/Unix 的纪元是 1970 年 1 月 1 日 00:00:00 UTC,GPS 的纪元是 1980 年 1 月 6 日 00:00:00 UTC,伽利略(欧盟的 GPS 系统)的纪元是 1999 年 8 月 21 日 23:59:47 UTC,北斗系统的纪元是 2006 年 1 月 1 日 00:00:00 UTC。其中,GPS、伽利略和北斗系统都明智地忽略了闰秒,把这些麻烦事留给人类去处理。而我们常用的 POSIX/Unix 的 “time_t” 时间戳,除了在闰秒期间可能会有歧义(不过闰秒以后可能也不会再有了),其他时候还是很可靠的。

为了在时间戳和人类可读的时间格式之间进行转换,UNIX 提供了 struct tm 结构体,它包含了年、月、日、时、分、秒等时间信息:

struct tm {int  tm_sec;    /* 秒 [0, 60] */int  tm_min;    /* 分 [0, 59] */int  tm_hour;   /* 时 [0, 23] */int  tm_mday;   /* 一个月中的第几天 [1, 31] */int  tm_mon;    /* 月份 [0, 11] (一月是 0) */int  tm_year;   /* 年份减去 1900 */int  tm_wday;   /* 一周中的第几天 [0, 6] (周日是 0) */int  tm_yday;   /* 一年中的第几天 [0, 365] (1 月 1 日是 0) */int  tm_isdst;  /* 夏令时标志 */long tm_gmtoff; /* 相对于 UTC 的秒数 */const char *tm_zone;   /* 时区缩写 */
};

不过,这个结构体的设计其实有点冗余,像一周中的第几天和一年中的第几天,通过其他字段就能推算出来。而且,tm_gmtofftm_zone 和 tm_isdst 这几个字段的含义不仅定义得不太清晰,理解起来也有难度,并且它们的作用还会根据结构体的使用方式而变化。

struct tm 的一个重要作用是作为 mktime() 函数的输入,mktime() 会把 “根据本地时区拆分的时间” 转换为 Unix 时间戳。但它的功能可不止这一个,它还会对传入的 struct tm 进行标准化处理。比如说,如果你想把当前时间往后调一周,你可能会直接给 time_t 时间戳加上 604800 秒(一周的秒数),但如果这个调整跨越了夏令时的边界,你原本下午 2 点的约会可能就会变成下周下午 1 点或 3 点,这可不是我们想要的结果。而 mktime() 就能帮你处理这种情况,即使你传入像 “3 月 35 日” 这样不合理的日期,它也能帮你修正。不过,使用 mktime() 时也有一些需要注意的地方,下面我们就来详细说说。

三、mktime() 的使用与注意事项

先来看个例子:

struct tm tm = {.tm_hour=14, .tm_mday = 28,
.tm_mon = 2, .tm_year = 2025 - 1900,
.tm_isdst = -1};  // <- 注意这里的 -1
time_t t = mktime(&tm);
cout << "original:         "<< ctime(&t);
tm.tm_mday += 7;
t = mktime(&tm);
cout << "mktime adjusted:  "<< ctime(&t);

在欧洲 / 阿姆斯特丹时区,这段代码的输出结果是:

original:        Fri Mar 28 14:00:00 2025
mktime adjusted: Fri Apr  4 15:00:00 2025

为什么我们的约会时间会偏移一个小时呢?问题就出在 tm.tm_isdst 这个字段上。mktime() 要求你明确指定时间是否处于夏令时,或者让它自己去判断(我们一开始把 tm.tm_isdst 设置为 -1 就是让它自己判断)。当我们第一次调用 mktime() 时,它发现初始时间不在夏令时,就把 tm_isdst 设置为 0。第二次调用时,这个设置没有改变,但新的时间其实是处于夏令时的,所以就出现了时间偏移的情况。解决办法就是在第二次调用 mktime() 之前,把 tm_isdst 重新设置为 -1。

另外,使用 mktime() 处理 UTC 时间时也有个大坑。mktime() 会把传入的时间当作 “本地时间” 来处理,所以如果你要处理 UTC 时间,就需要在调用 mktime() 之前把时区设置为 UTC。但如果你的程序有其他线程在运行,修改整个应用程序的时区可能会产生副作用。不过,多线程程序本来就不能随意更改环境变量,所以这个方法也行不通。

还好,有一个非标准但广泛可用的函数 timegm() 能很好地解决 UTC 时间的处理问题。从 IEEE Std 1003.1 - 2024 标准中可知,“未来的标准版本预计会添加一个 timegm() 函数,它与 mktime() 类似,但 timeptr 指向的 tm 结构体包含的是协调世界时(UTC)的拆分时间”。在 Windows 系统上,timegm() 对应的函数是 mkgmtime()。如果你的系统是 AIX,没有 timegm() 函数,也可以在特定的地方找到独立的实现。

总结一下使用 mktime() 和 timegm()(或 mkgmtime())的要点:

  • 使用 mktime() 处理本地时间时,把 tm_isdst 设置为 -1,这通常符合人们的预期,但在夏令时切换时,可能会随机得到两个 “02:30”(或类似时间点)中的一个。

  • 在填充 struct tm 之前,最好先把其他字段清零,以防万一。

  • 要知道 mktime() 会修改传入的 struct tm,可能会产生副作用,所以在重复使用 struct tm 之前,至少要重置 tm_isdst

  • 不管你怎么设置 tm_gmtoffset 或 tm_zonemktime() 都会使用当前时区。如果你想让它把 struct tm 当作 UTC 时间处理,就需要设置 TZ 环境变量为 UTC,但这会影响其他做时间操作的线程。所以,能使用 timegm() 或 mkgmtime() 就尽量用它们。

四、解析 UTC 时间字符串

我们都希望能把像 “Fri, 17 Jan 2025 06:07:07 GMT” 这样的时间字符串直接传入 strptime() 函数,然后得到一个合理的 struct tm 结构体。但 Linux glibc 的 strptime() 手册中关于 %z 和 %Z 这两个时区格式说明符的描述含糊不清,让人摸不着头脑。很多人可能会期望用 strptime() 结合 %Z(用于解析 “GMT”),再配合 mktime() 就能把 UTC 时间字符串转换为 Unix 时间戳,但实际上 mktime() 根本不会看 tm_gmtoffset 和 tm_zone 这两个字段,所以即使 strptime() 做对了,也无法实现我们的目标,而且它还真就做不对。

截至 2024 年,虽然 Open Group 对 strptime() 有了更详细的规范,但里面也都是些让人无奈的消息。strptime() 对 %z 没有明确的行为定义,这个原本应该用来处理 “+0200” 这种偏移标识符的符号,现在根本靠不住。对于 %Z,虽然有一些说明,但作用也非常有限。只有在特定的本地化设置下,它才可能设置 tm_isdst 的正确值,而且像 “EST” 这样的字符串,由于没有明确的定义,也很难通过 %Z 来解析。

不过,既然我们知道了 timegm() 这个好帮手,就可以忽略 %z 和 %Z 了。

五、strptime() 与本地化问题

在很多情况下,我们需要解析包含英文日期和月份名称的时间字符串,并且希望 strptime() 能正确处理。但 IEEE/Open Group 标准规定,strptime() 的转换操作是由当前本地化设置的 LC_TIME 类别决定的。这里有个容易忽略的点,C 和 C++ 程序默认使用的是 “C” 本地化,这实际上就是美式英语。这对于解析数据中的时间字符串来说通常是好事,因为这些字符串大多是英文的。

但如果你的程序调用了 setlocale() 函数,设置了非 “C” 的本地化,那你的程序可能就只能处理特定语言(比如荷兰语)的时间字符串了,这可就麻烦了。你可能会想在调用 strptime() 之前把本地化设置为 “C”,用完再改回来,但 setlocale() 在多线程程序中调用并不安全(除了在线程启动之前),而且即使安全调用,也可能会影响其他线程的输出。

所以,一般来说,如果你需要解析特定的时间字符串并且想用 strptime(),一定要确保程序处于你期望的本地化环境中。虽然有 strftime_l() 函数可以指定格式化时间时使用的本地化,但并没有官方可用的 strptime_l() 函数。

当然,你也可以自己解析像 “17 Jan 2025 06:07:07” 这样的字符串,填充 struct tm 结构体,然后让 mktime() 来计算 Unix 时间戳,这也是一种可行的办法。

六、用 C++ 解决本地化问题及 C++20 的强大时间处理功能

C++ 的输入输出流(iostreams)在处理本地化方面比 C/POSIX 做得更好。在 C++ 中,你可以为每个输入输出流设置本地化。下面是一个 C++ 辅助函数,如果你在设置了本地化的 C 程序中需要解析任意 UTC 时间字符串,可以调用这个函数:

extern "C"
int utcstr2epoch(const char* timestr, const char* fmtstr, struct tm* output)
{std::tm t = {}; // tm_isdst = 0, 不用考虑夏令时,这是 UTC 时间std::istringstream ss(timestr);ss.imbue(std::locale()); // "LANG=C", 但本地化设置是本地的ss >> std::get_time(&t, fmtstr);if (ss.fail())return -1;// 修正星期几、一年中的第几天等字段t.tm_isdst = 0; // 不用考虑夏令时t.tm_wday = -1;if(mktime(&t) == -1 && t.tm_wday == -1) // "真正的错误"return -1;*output = t;return 0;
}

这个函数还展示了如何处理 mktime() 的错误。当 mktime() 处理 1969 年 12 月 31 日 23:59 这样的时间时,会返回 -1 作为错误代码。我们可以用 tm_wday 作为标志来判断是否有数据被处理,以此确定是否发生了错误。

另外,还有一个基于 C 的小示例程序,它可以解析英文的 UTC 时间戳,并使用调用环境的本地化设置来打印时间:

$ LC_TIME="nl_NL.utf-8" ./utcparse "1 Jan 1970 00:00:00" "%d %b %Y %H:%M:%S"
UTC Time: donderdag,  1 januari 1970 00:00:00, day of year 001
time_t:   0

到了 C++20 及更高版本,更是引入了强大的时区数据库。虽然这个功能还没有在所有编译器上都可用,但预标准化版本可以单独使用。比如下面这个超酷的例子:

auto meet_nyc = make_zoned("America/New_York",
date::local_days{Monday[1]/May/2016} + 9h);
auto meet_lon = make_zoned("Europe/London",    meet_nyc);
auto meet_syd = make_zoned("Australia/Sydney", meet_nyc);
cout << "The New York meeting is " << meet_nyc << '\n';
cout << "The London   meeting is " << meet_lon << '\n';
cout << "The Sydney   meeting is " << meet_syd << '\n';

这段代码选择了 “2016 年 5 月的第一个星期一,纽约当地时间上午 9 点”,然后轻松地将其转换为另外两个时区的时间:

The New York meeting is 2016-05-02 09:00:00 EDT
The London   meeting is 2016-05-02 14:00:00 BST
The Sydney   meeting is 2016-05-02 23:00:00 AEST

更厉害的是,这个时区库不仅可以使用操作系统的时区数据库(可能缺少关键的闰秒细节),还能直接从 IANA tzdb 获取数据。这意味着你可以精确计算 1978 年一次航班飞行的实际时长,即使这次飞行跨越了夏令时变化和闰秒,也不在话下。

在 C 和 C++ 中从 UTC 日期时间字符串获取 Unix 时间戳确实充满挑战,但只要掌握了正确的方法,也能轻松应对。希望今天的分享能让你在处理时间相关的编程问题时更加得心应手。

科技脉搏,每日跳动。

与敖行客 Allthinker一起,创造属于开发者的多彩世界。

图片

- 智慧链接 思想协作 -

相关文章:

从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案

在编程世界里&#xff0c;从 UTC 日期时间字符串获取 Unix 时间戳&#xff0c;看似简单&#xff0c;实则暗藏玄机。你以为输入一个像 “Fri, 17 Jan 2025 06:07:07” 这样的 UTC 时间&#xff0c;然后轻松得到 1737094027&#xff08;从 1970 年 1 月 1 日 00:00:00 UTC 开始经…...

[前端开发]记录国内快速cdn库,用于在线引入JavaScript第三方库

字节跳动的两个库,官网地址如下,搜索时优先找第一个,可用来链接axios,Boostrap等等第三方库 1. 字节跳动静态资源公共库 比如说搜索lodash,用于节流防抖的库,点击复制即可,一般是****.js或****.min.js这样的为后缀名的链接 点击复制即可, <script src"https://lf9-cd…...

留学生scratch计算机haskell函数ocaml编程ruby语言prolog作业VB

您列出了一系列编程语言和技术&#xff0c;这些可能是您在留学期间需要学习或完成作业的内容。以下是对每个项目的简要说明和它们可能涉及的领域或用途&#xff1a; Scratch&#xff1a; Scratch是一种图形化编程语言&#xff0c;专为儿童和初学者设计&#xff0c;用于教授编程…...

CF 766A.Mahmoud and Longest Uncommon Subsequence(Java实现)

题目分析 (小何同学语文不太好&#xff0c;看这个题弯弯绕绕&#xff0c;看不懂一点&#xff0c;哈哈哈。)在尝试示例中分析之后&#xff0c;题目的意思大概就是&#xff0c;两个字符串相同就输出-1&#xff0c;不同就输出最长的那个字符串长度 思路分析 数据输入存值之后&…...

React 的 12 个核心概念

文章目录 一、JSX&#xff1a;逻辑与视图的桥梁二、组件&#xff1a;模块化构建的核心三、Props&#xff1a;单向数据流的基石四、State&#xff1a;动态交互的核心五、useEffect&#xff1a;副作用管理的利器六、Context&#xff1a;跨层级数据共享的利器七、React.memo&#…...

玩转大语言模型——使用langchain和Ollama本地部署大语言模型

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型——使用GraphRAGOllama构建知识图谱 玩转大语言模型——完美解决Gra…...

【数据结构】(2)时间、空间复杂度

一、衡量算法好坏的指标 时间复杂度衡量算法的运行速度&#xff0c;空间复杂度衡量算法所需的额外空间。这些指标&#xff0c;是某场景中选择使用哪种数据结构和算法的依据。如今&#xff0c;计算机的存储器已经变得容易获得&#xff0c;所以不再太关注空间复杂度。 二、渐进表…...

分享14分数据分析相关ChatGPT提示词

数据分析 在研究过程中数据分析扮演着至关重要的角色&#xff0c;它能够帮助研究者从海量数据中提取有价值的信息&#xff0c;从而为研究结论提供坚实的依据。而ChatGPT在数据分析领域展现出了强大的辅助能力&#xff0c;为研究者提供了全方位的支持。当研究者提供清晰且具体的…...

dify实现原理分析-rag-数据检索的实现

数据检索的总体执行步骤 数据检索总体步骤如下&#xff1a; #mermaid-svg-YCRNdSE7T1d0Etyj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YCRNdSE7T1d0Etyj .error-icon{fill:#552222;}#mermaid-svg-YCRNdSE7T1d…...

Day30-【AI思考】-错题分类进阶体系——12维错误定位模型

文章目录 错题分类进阶体系——12维错误定位模型**一、认知层错误&#xff08;根源性缺陷&#xff09;****二、操作层错误&#xff08;执行过程偏差&#xff09;****三、心理层错误&#xff08;元认知障碍&#xff09;****四、进阶错误&#xff08;专业级陷阱&#xff09;** 错…...

全国31省空间权重矩阵(地理相邻空间、公路铁路地理距离空间、经济空间)权重矩阵数据-社科数据

中国31个省份空间权重矩阵-社科数据https://download.csdn.net/download/paofuluolijiang/90028597 https://download.csdn.net/download/paofuluolijiang/90028597 空间权重矩阵是反映个体在空间中依赖关系的矩阵&#xff0c;本数据计算全国31个省三种标准化处理的空间权重矩…...

Docker容器数据恢复

Docker容器数据恢复 1 创建mongo数据库时未挂载数据到宿主机2 查找数据卷位置3 将容器在宿主机上的数据复制到指定目录下4 修改docker-compose并挂载数据&#xff08;注意端口&#xff09;5 重新运行新容器 以mongodb8.0.3为例。 1 创建mongo数据库时未挂载数据到宿主机 versi…...

Visual Studio使用GitHub Copilot提高.NET开发工作效率

GitHub Copilot介绍 GitHub Copilot 是一款 AI 编码助手&#xff0c;可帮助你更快、更省力地编写代码&#xff0c;从而将更多精力集中在问题解决和协作上。 GitHub Copilot Free包含哪些功能&#xff1f; 每月 2000 代码补全&#xff0c;帮助开发者快速完成代码编写。 每月 …...

【matlab】绘图 离散数据--->连续函数

matlab绘图练习 离散数据及离散函数对离散区间进行细划分 达到连续效果画plot(y)图 与 复数的应用 离散数据及离散函数 例1 x1[1 2 4 6 7 8 10 11 12 14 16 17 18 20] y1[1 2 4 6 7 8 10 10 8 7 6 4 2 1] figure(1); plot(x1,y1,o,MarkerSize,15); x21:20; y2log(x2); figure…...

Python大数据可视化:基于python的电影天堂数据可视化_django+hive

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 电影数据 看板展示 我的信息 摘要 电影天堂数据可视化是…...

几种K8s运维管理平台对比说明

目录 深入体验**结论**对比分析表格**1. 功能对比****2. 用户界面****3. 多租户支持****4. DevOps支持** 细对比分析1. **Kuboard**2. **xkube**3. **KubeSphere**4. **Dashboard****对比总结** 深入体验 KuboardxkubeKubeSphereDashboard 结论 如果您需要一个功能全面且适合…...

YOLO11/ultralytics:环境搭建

前言 人工智能物体识别行业应该已经饱和了吧&#xff1f;或许现在并不是一个好的入行时候。 最近看到了各种各样相关的扩展应用&#xff0c;为了理解它&#xff0c;我不得不去尝试了解一下。 我选择了git里非常受欢迎的yolo系列&#xff0c;并尝试了最新版本YOLO11或者叫它ultr…...

Effective Objective-C 2.0 读书笔记—— 消息转发

Effective Objective-C 2.0 读书笔记—— 消息转发 文章目录 Effective Objective-C 2.0 读书笔记—— 消息转发前言消息转发机制概述动态方法解析处理dynamic的属性用于懒加载 消息转发快速消息转发完整消息转发 总结 前言 在前面我学习了关联对象和objc_msgSend的相关内容&a…...

【Python-办公自动化】实现自动化输出json数据类型的分析报告和正逆转换

分析报告 import json from pprint import pprint, PrettyPrinterdef analyze_energy_data(file_path):"""能源数据分析与结构查看函数参数:file_path (str): JSON文件路径功能:1. 加载并解析JSON数据2. 显示数据结构概览3. 交互式结构探索"""…...

Docker小游戏 | 使用Docker部署RPG网页小游戏

Docker小游戏 | 使用Docker部署RPG网页小游戏 前言一、项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署RPG网页小游戏下载镜像创建容器检查容器状态检查服务端口安全设置四、访问RPG网页小游戏五、总结前言 随着互联网技术的不断…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...