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

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。

相关文章:

  • 中银基金软件开发工程师春招群面记录
  • 网络安全之BGP详解
  • 通过管理系统完成商品属性维护
  • vue3 + antd-vue@4 a-table单元格合并,rowSpan(行合并),colSpan(列合并)详解, 表头合并详解, 表头自定义详解
  • docker 配置文件使用经验,后续持续增加
  • 设计模式7——建造者模式
  • 保护共享资源的方法(互斥锁)
  • Spring框架中获取方法参数名称:DefaultParameterNameDiscoverer
  • 开发人员容易被骗的原因有很多,涉及技术、安全意识、社会工程学以及工作环境等方面。以下是一些常见原因:
  • 揭秘指针魔法,让你的编程之旅如虎添翼!‍♂️✨
  • 赶紧收藏!2024 年最常见 20道 Redis面试题(三)
  • 前端 CSS 经典:好看的标题动画
  • 深度学习之基于YOLOV5的口罩检测系统
  • mysql--数据库表的创建及基础命令
  • ACL的几种类型
  • Angular6错误 Service: No provider for Renderer2
  • C# 免费离线人脸识别 2.0 Demo
  • Fabric架构演变之路
  • Java 网络编程(2):UDP 的使用
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Js基础知识(四) - js运行原理与机制
  • maven工程打包jar以及java jar命令的classpath使用
  • python docx文档转html页面
  • Wamp集成环境 添加PHP的新版本
  • 工程优化暨babel升级小记
  • 前端存储 - localStorage
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 小程序开发之路(一)
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • #{} 和 ${}区别
  • #{}和${}的区别是什么 -- java面试
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (rabbitmq的高级特性)消息可靠性
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (五)Python 垃圾回收机制
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (一)Dubbo快速入门、介绍、使用
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转) Face-Resources
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .NET/C# 使窗口永不获得焦点
  • .net对接阿里云CSB服务
  • .NET企业级应用架构设计系列之结尾篇
  • .考试倒计时43天!来提分啦!
  • /var/log/cvslog 太大
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • @Query中countQuery的介绍
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [.net] 如何在mail的加入正文显示图片
  • [20150707]外部表与rowid.txt