C++ 时间处理-从字符串中解析日期时间

  • 1. 关键词
  • 2. 问题
  • 3. 解决思路
  • 4. 代码实现
  • 5. 测试代码
  • 6. 运行结果
  • 7. 源码地址

1. 关键词

C++ 时间处理 从字符串中解析日期时间 跨平台

2. 问题

C++如何将字符串的日期时间解析成对应的时间戳?

3. 解决思路

  • 可以用正则表达式将字符串解析成 struct tm 类型的对象。
  • mktime()函数可以将 struct tm 类型的时间转换成时间戳。

4. 代码实现


#include <cstdint>
#include <string>
#include <vector>
#include <regex>
#include <time.h>using time_regex_type = std::pair<std::string, std::regex>;
using time_regex_vec_type = std::vector<time_regex_type>;std::string supported_time_formats(const time_regex_vec_type &fmtlist)
{std::string time_fmts;for (size_t i = 0; i < fmtlist.size(); i++){time_fmts += fmtlist[i].first + "\n";}return time_fmts;
}bool datetime::verify_time(const struct tm &time)
{// 校验年if (time.tm_year < 1900){CUTL_ERROR("the year should be >= 1900");return false;}// 校验月if (time.tm_mon < 1 || time.tm_mon > 12){CUTL_ERROR("the month should be between 1 and 12");return false;}// 校验日std::vector<int> large_month = {1, 3, 5, 7, 8, 10, 12};if (std::find(large_month.begin(), large_month.end(), time.tm_mon) != large_month.end() && (time.tm_mday < 1 || time.tm_mday > 31)){CUTL_ERROR("the day should be between 1 and 31 for " + std::to_string(time.tm_mon) + " month");return false;}std::vector<int> small_month = {4, 6, 9, 11};if (std::find(small_month.begin(), small_month.end(), time.tm_mon) != small_month.end() && (time.tm_mday < 1 || time.tm_mday > 30)){CUTL_ERROR("the day should be between 1 and 30 for " + std::to_string(time.tm_mon) + " month");return false;}if (time.tm_mon == 2){auto is_leap_year = [](int year){ return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); };if (is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 29)){CUTL_ERROR("the day should be between 1 and 29 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));return false;}if (!is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 28)){CUTL_ERROR("the day should be between 1 and 28 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));return false;}}// 校验时分秒if (time.tm_hour < 0 || time.tm_hour > 23){CUTL_ERROR("the hour should be between 0 and 23");return false;}if (time.tm_min < 0 || time.tm_min > 59){CUTL_ERROR("the minute should be between 0 and 59");return false;}if (time.tm_sec < 0 || time.tm_sec > 59){CUTL_ERROR("the second should be between 0 and 59");return false;}return true;
}uint64_t parse_datetime(const std::string &time_text, int isdst)
{std::smatch matchRes;bool result = false;static time_regex_vec_type fmt_list = {// 0/1, 2/3, 4/5, 6/7的顺序不能反,因为不含毫秒数的时间会被优先匹配到std::make_pair("YYYY-MM-DD HH:MM:SS.sss", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),std::make_pair("YYYY-MM-DD HH:MM:SS", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),std::make_pair("YYYY.MM.DD HH:MM:SS.sss", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),std::make_pair("YYYY.MM.DD HH:MM:SS", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),std::make_pair("YYYY/MM/DD HH:MM:SS.sss", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),std::make_pair("YYYY/MM/DD HH:MM:SS", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),std::make_pair("YYYYMMDD HH:MM:SS.sss", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),std::make_pair("YYYYMMDD HH:MM:SS", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),};for (size_t i = 0; i < fmt_list.size(); i++){auto &fmt_text = fmt_list[i].first;auto &fmt_pattern = fmt_list[i].second;result = std::regex_search(time_text, matchRes, fmt_pattern);if (result){CUTL_DEBUG("matched regex: " + fmt_text);break;}}if (!result || matchRes.size() < 7){auto time_fmts = supported_time_formats(fmt_list);CUTL_ERROR("Only the following time formats are supported:\n" + time_fmts);return 0;}CUTL_DEBUG("matchRes size:" + std::to_string(matchRes.size()) + ", res:" + matchRes[0].str());// 解析毫秒值int ms = 0;if (matchRes.size() == 8){ms = std::stoi(matchRes[7].str());}// 解析tm结构的时间struct tm time = {};if (matchRes.size() >= 7){for (size_t i = 1; i < 7; i++){time.tm_year = std::stoi(matchRes[1]);time.tm_mon = std::stoi(matchRes[2]);time.tm_mday = std::stoi(matchRes[3]);time.tm_hour = std::stoi(matchRes[4]);time.tm_min = std::stoi(matchRes[5]);time.tm_sec = std::stoi(matchRes[6]);time.tm_isdst = isdst;}}if (!verify_time(time)){return 0;}// 转换为时间戳time.tm_year -= 1900;time.tm_mon -= 1;auto ret = mktime(&time);if (ret == -1){CUTL_ERROR("mktime() failed");return 0;}auto s = static_cast<uint64_t>(ret);return s;
}

5. 测试代码

#pragma once#include <iostream>
#include "timecount.h"
#include "common.hpp"void TestDatetimeParseString()
{// 字符串解析成时间PrintSubTitle("TestDatetimeParseString");auto dt0 = parse_datetime(" 2024-03-02 14:18:44 ");std::cout << "dt0: " << dt0 << std::endl;auto dt2 = parse_datetime(" 2024.03.12 14:18:44");std::cout << "dt2: " << dt2 << std::endl;
}

6. 运行结果

--------------------------------------TestDatetimeParseString---------------------------------------
dt0: 2024-03-02 14:18:44.000
dt2: 2024-03-12 14:18:44.000

7. 源码地址

更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/13633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java数据结构与算法(栈判断回文链表)

前言 回文链表的判断最适合用栈。 实现原理 1.找到链表中间节点。 2.反转后半段节点。 3.从头比较链表头节点的值和反转后的链表值。 具体代码实现 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode…

Spring Boot:SpringBoot 如何优雅地定制JSON响应数据返回

一、前言 目前微服务项目中RESTful API已经是前后端对接数据格式的标配模式了&#xff0c;RESTful API是一种基于REST&#xff08;Representational State Transfer&#xff0c;表述性状态转移&#xff09;原则的应用程序编程接口&#xff08;Application Programming Interfac…

了解Project

可以用来制定范围管理计划(WBS)&#xff0c;进度管理计划&#xff0c;资源分配&#xff0c;计算成本&#xff0c;跟踪进度&#xff0c;汇报进度 编制进度计划步骤&#xff1a;创建工作分解结构—建立工作之间的依赖关系—估计工作周期 工时和小时&#xff1a;小时是连续工作&am…

如何在iClone中使用Curve Editor精细调整PuppetClip

在3D动画制作过程中&#xff0c;iClone软件提供了强大的工具来创造和调整角色的面部表情。其中&#xff0c;PuppetClip是一个非常实用的功能&#xff0c;它允许动画师捕捉和记录面部动作。但有时候&#xff0c;我们在Curve Editor中却看不到这些动作的关键帧和曲线。这篇博客将…

P6【知识点】【数据结构】【树tree】C++版

树是由一个集合以及在该集合上定义的一种关系构成的&#xff0c;集合中的元素称为树的结点&#xff0c;所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构&#xff0c;在这种层次结构中有一个结点具有特殊的地位&#xff0c;这个结点称为该树的根结点。 二叉…

大数据——大数据架构

一&#xff1a;大数据应用场景 1.离线批处理 数据量比较大&#xff0c;延迟比较高 2.实时检索 实时检索中的hbase按key值检索较快&#xff0c;因为其存储是顺序存储&#xff0c;但是对value的检索就相对较慢。 数据量大&#xff0c;实时查询数据&#xff0c;不能对数据做大量…

数据结构(二)单链表

一、链表 &#xff08;一&#xff09;概念 逻辑结构&#xff1a;线性 存储结构&#xff1a;链式存储&#xff0c;在内存中不连续 分为有头链表和无头链表 同时又细分为单向、循环、双向链表 &#xff08;二&#xff09;有头单向链表示意图 以下数据及地址只是为了方便理解…

点云文件pcd基础介绍

我们在做高精地图开发或者相关GIS项目开发的的时候&#xff0c;经常会遇到点云这个问题&#xff0c;点云 想到什么 &#xff0c;当然是PCD文件了。这里整体过一遍pcd 文件。 概述 PCD文件格式是PCL库中使用最广泛且独有的数据格式&#xff0c;旨在补充现有文件格式&#xff0…

Colab/PyTorch - 006 Mask RCNN Instance Segmentation

Colab/PyTorch - 006 Mask RCNN Instance Segmentation 1. 源由2. 用 PyTorch 实现 Mask R-CNN2.1 输入输出2.2 预训练模型2.3 模型预测2.4 目标检测流程2.5 推理示例一示例二示例三 3. 推断时间比较(CPU v.s. GPU)4. 总结5. 参考资料 1. 源由 在《Colab/PyTorch - 004 Torchv…

vue2组件的封装+antd

1.vue2表格的封装使用 表格使用 <standard-tables:columns"columns":dataSource"dataSource":loading"loading"bordered:pagination"{ ...pagination, onChange: onPageChange }"><div slot"warnType" slot-scope…

必应bing国内推广开户,全方位必应广告开户流程介绍!

在所有获客渠道中&#xff0c;搜索引擎广告成为企业扩大品牌影响力、精准触达目标客户的关键途径之一。作为全球领先的搜索引擎之一&#xff0c;必应&#xff08;Bing&#xff09;拥有庞大的用户群体和独特的市场优势&#xff0c;是企业不可忽视的营销阵地。云衔科技&#xff0…

Linux驱动---输入子系统

1.概述 1.1 什么叫做输入子系统 简单来说&#xff0c;输入子系统就是统一各种各样的输入设备的系统&#xff1b; 常见的输入设备比如: 键盘、触摸屏、按键、鼠标。 1.2 为什么要引入输入子系统 每个人写驱动代码都有自己的风格和习惯&#xff0c;导致代码会有一定的差异&…

qt面试经验

目录 1.qt底层原理2.connect的第五个参数3.信号槽的原理4.qt的智能指针QPointerQSharedPointerQScopedPointerQWeakPointerQSharedDataPointerQScopedArrayPointer 5.线程6.事件监听全局事件监听某一类控件的事件监听某一个控件的事件Qt的事件循环事件与信号的区别 7.设计模式单…

python工程打包为一个可执行的exe文件

文章目录 背景步骤安装 PyInstaller打包python脚本生成的文件特殊情况 示例 背景 打包一个Python工程为一个可执行的exe文件&#xff0c;效果是&#xff1a;打包完成之后&#xff0c;这个exe文件在没有python环境的电脑也能运行&#xff0c;不需要安装额外的环境 步骤 安装 P…

vscode添加代办相关插件,提高开发效率

这里写目录标题 前言插件添加添加TODO Highlight安装TODO Highlight在项目中自定义需要高亮显示的关键字 TODO Tree安装TODO Tree插件 单行注释快捷键 前言 在前端开发中&#xff0c;我们经常会遇到一些未完成、有问题或需要修复的部分&#xff0c;但又暂时未完成或未确定如何处…

kafka监控配置和告警配置

Kafka的监控配置和告警配置是确保Kafka集群稳定运行的关键部分。以下是一些关于Kafka监控配置和告警配置的建议&#xff1a; 一、Kafka监控配置 集群级别参数监控&#xff1a; log.retention.hours&#xff1a;用于控制消息在日志中保留的时间。监控此参数的值&#xff0c;确…

【MySQL精通之路】AdminAPI-使用

目录 1.使用 1.1 使用场景 1.2 使用模式 官方文档&#xff1a; MySQL :: MySQL Shell 8.0 :: 6.1 Using MySQL AdminAPI 本文介绍MySQL SHELL提供的MySQL AdminAPI&#xff0c;使您能够管理MySQL实例&#xff0c;使用它们创建InnoDB Cluster、InnoDB ClusterSet和InnoDB R…

合约的值类型

基本数据类型&#xff1a;整数、枚举、布尔&#xff08;类似java的数据类型&#xff09;Address、Contract&#xff08;这两种是solidity特有的数据类型&#xff09;Fixed byte array&#xff08;定长字节数组&#xff09; Integer(int/uint) int/uint 以8位字节递增&#xf…

推荐ChatGPT4.0——数学建模

1.建模助手 2. 可直接上传文档分析 3.获取途径 现在商家有活动&#xff0c;仅仅需要19.9&#xff01;&#xff01;&#xff01;&#xff01; 现在有优惠&#xff1a; 推荐人写&#xff1a;love 周卡&#xff0c;半月卡&#xff0c;月卡优惠码是love&#xff0c; 会优惠10元…

一篇讲透排序算法之插入排序and选择排序

1.插入排序 1.1算法思想 先将数组的第一个元素当作有序&#xff0c;让其后一个元素与其比较&#xff0c;如果比第一个元素小则互换位置&#xff0c;之后再将前两个元素当作有序的&#xff0c;让第三个元素与前两个元素倒着依次进行比较&#xff0c;如果第三个元素比第二个元素…