我只能使用C ++标准库(C ++ 14)将时间戳转换为给定的格式date-time。我是C ++的新手,我知道C ++通过Java之类的库对我们的支持并不多。 在给定的日期和时间 2011-03-10 11:23:56在中欧时区(CET)中, 将产生标准格式的输出:“ 2011-03-10T11:23:56.123 + 0100 ”。
std::string format = "yyyy-MM-dd'T'HH:mm:ss'.'SSSZ"; //default format
auto duration = std::chrono::system_clock::now().time_since_epoch();
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
我的格式字符串语法为
G : Era
yy,yyyy : year (two digits/four digits)
M,MM : month in number (without zero/ with zero) - (e.g.,1/01)
MMM,MMMM : month in text (shortname/fullname)- (e.g.,jan/january)
d,dd : day in month (without zero/with zero)- (e.g.,1/01)
D : day in year
F : day of week of month
E, EEEE : day of week
h,hh : hours(1-12) (without zero/with zero)- (e.g.,1/01)
H,HH : hours(0-23) (without zero/with zero)- (e.g.,1/01)
m,mm : minutes (without zero/with zero)- (e.g.,1/01)
s,ss : seconds (without zero/with zero)- (e.g.,1/01)
S,SS,SSS : milliseconds
w,W : Week in year (without zero/with zero)- (e.g.,1/01)
a : AM/PM
z,zzzz : timezone name
答案 0 :(得分:1)
这是一个棘手的问题,因为:
没有明确说明输入是什么。但是从示例代码中,我将假设std::chrono::system_clock::time_point
。
重要的是要认识到中欧时区(CET)被定义为time zone with a fixed UTC offset of 1h。有些地理区域全年遵循该时区规则,有些则没有。而且没有人一直跟随它。无论如何,问题的这一部分使我们能够对所涉及的UTC偏移进行硬编码:1h。没有夏令时调整。
在C ++ 14中,有两种方法可以在不涉及受版权保护(甚至是开源)的第三方软件的情况下完成此操作:
使用C API。
滚动自己的图片。
1的问题是它容易出错。它不能直接处理毫秒精度。它不直接处理特定时区,例如CET。 C API仅知道UTC和计算机的本地设置时区。但是这些问题是可以克服的。
2的问题在于它涉及非直观的算法,用于从std::chrono::system_clock::time_point
中提取年,月和日字段。
尽管有2的问题,但这是我更喜欢的解决方案,我将在下面介绍。我还将展示C ++ 20如何使很多变得更容易。
在所有解决方案中,我将通过实现以下形式的函数来形式化输入和输出:
std::string format_CET(std::chrono::system_clock::time_point tp);
有六个离散步骤。它将需要这些标头,而无需其他标头:
#include <chrono>
#include <string>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
A。将输入移位+1小时UTC偏移量。
// shift time_point to CET
tp += 1h;
将函数本地化的using指令很方便地将UDL h
纳入范围,以及此函数中<chrono>
所需的其他所有内容:
using namespace std::chrono;
B。得到time_point tp
的两种变体:一种具有毫秒精度,一种具有日精度:
// Get time_points with both millisecond and day precision
auto tp_ms = time_point_cast<milliseconds>(tp);
auto tp_d = time_point_cast<days>(tp_ms);
重要的是要了解这两个强制转换都趋近于零,并且在负时间点会给出错误的结果。 system_clock
在其1970年1月1日00:00:00 UTC时期之前给出负的时间点。 C ++ 17引入了floor<millliseconds>(tp)
来解决此问题。
日精度time_point
将用于提取年,月和日字段,毫秒精度time_point
将用于提取小时,分钟,秒和毫秒字段。上面使用的duration days
直到C ++ 20才被添加,但是您可以使用以下方法实现:
using days = std::chrono::duration<int, std::ratio<86400>>;
C。要从tp_d
获取年,月和日字段,可以方便地使用public domain algorithms for calendrical operations之一。这不是第三方图书馆。它是用于编写自己的日历库的算法(这就是我正在解释的内容)。我已经定制了civil_from_days
算法来精确解决format_CET
的需求:
// Get {y, m, d} from tp_d
auto z = tp_d.time_since_epoch().count();
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
z += 719468;
const int era = (z >= 0 ? z : z - 146096) / 146097;
const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
int y = static_cast<int>(yoe) + era * 400;
const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
const unsigned mp = (5*doy + 2)/153; // [0, 11]
const unsigned d = doy - (153*mp+2)/5 + 1; // [1, 31]
const unsigned m = mp + (mp < 10 ? 3 : -9); // [1, 12]
y += (m <= 2);
在上面链接的站点上,对于想要了解其工作原理的人,该方法有详尽详尽的推论。
此时,积分变量{y, m, d}
包含年,月,日三元组。
D。获取自当地午夜以来的持续时间。这将用于提取当地时间:
// Get milliseconds since the local midnight
auto ms = tp_ms - tp_d;
E。获取小时,分钟,秒和毫秒字段:
// Get {h, M, s, ms} from milliseconds since midnight
auto h = duration_cast<hours>(ms);
ms -= h;
auto M = duration_cast<minutes>(ms);
ms -= M;
auto s = duration_cast<seconds>(ms);
ms -= s;
此时,chrono::duration
变量{h, M, s, ms}
保留了所需的值。
F。现在我们准备格式化:
// Format {y, m, d, h, M, s, ms} as yyyy-MM-dd'T'HH:mm:ss'.'SSS+0100
std::ostringstream os;
os.fill('0');
os << std::setw(4) << y << '-' << std::setw(2) << m << '-' << std::setw(2)
<< d << 'T' << std::setw(2) << h.count() << ':'
<< std::setw(2) << M.count() << ':' << std::setw(2) << s.count()
<< '.' << std::setw(3) << ms.count() << "+0100";
return os.str();
使用操纵器setw
的组合来设置每个字段的宽度,并使用0
填充字符,将获得所需的前导零。
在C ++ 20规范草案中,这容易得多:
std::string
format_CET(std::chrono::system_clock::time_point tp)
{
using namespace std::chrono;
static auto const CET = locate_zone("Etc/GMT-1");
return std::format("{:%FT%T%z}", zoned_time{CET, floor<milliseconds>(tp)});
}
“ Etc / GMT-1”是中欧时区(CET)的IANA等效项。该time_zone const*
位于并存储在变量CET
中。 time_point tp
被截断为毫秒精度,并使用time_zone
与zoned_time
配对。然后使用显示的格式字符串对此zoned_time
进行格式化(以毫秒为单位)。
存在一个C ++ 20规范的开源(MIT许可)预览版,其语法差异很小here。
#include "date/tz.h"
std::string
format_CET(std::chrono::system_clock::time_point tp)
{
using namespace date;
using namespace std::chrono;
static auto const CET = locate_zone("Etc/GMT-1");
return format("%FT%T%z", zoned_time<milliseconds>{CET, floor<milliseconds>(tp)});
}
Some installation is required for Windows.
此预览确实适用于C ++ 14。在C ++ 17和更高版本中,zoned_time<milliseconds>
可以简化为zoned_time
。
还有一种使用预览库的方法,因此不需要安装。它成为 header-only 库。这是通过创建仅模拟CET的自定义时区,然后将其安装在zoned_time
中来完成的。这是自定义时区的样子:
#include "date/tz.h"
class CET
{
public:
template <class Duration>
auto
to_local(date::sys_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
return local_time<Duration>{(tp + 1h).time_since_epoch()};
}
template <class Duration>
auto
to_sys(date::local_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
return sys_time<Duration>{(tp - 1h).time_since_epoch()};
}
template <class Duration>
date::sys_info
get_info(date::sys_time<Duration>) const
{
using namespace date;
using namespace std::chrono;
return {ceil<seconds>(sys_time<milliseconds>::min()),
floor<seconds>(sys_time<milliseconds>::max()),
1h, 0min, "CET"};
}
const CET* operator->() const {return this;}
};
CET
现在满足了足够的时区要求,因此可以在zoned_time
中使用并按照以前的格式进行格式化。在C ++ 14中,语法很复杂,因为必须显式指定zoned_time
模板参数:
std::string
format_CET(std::chrono::system_clock::time_point tp)
{
using namespace date;
using namespace std::chrono;
using ZT = zoned_time<milliseconds, CET>;
return format("%FT%T%z", ZT{CET{}, floor<milliseconds>(tp)});
}
此选项也在C ++ 20规范中,其优点是时区缩写(在您的问题中未使用)将正确报告“ CET”而不是“ +01”。
找到有关自定义时区的更多文档here。
使用这些解决方案中的任何一种,现在都可以像下面这样行使功能:
#include <iostream>
int
main()
{
std::cout << format_CET(std::chrono::system_clock::now()) << '\n';
}
典型的输出如下所示:
2019-10-29T16:37:51.217+0100
答案 1 :(得分:0)
import { Injectable } from '@angular/core';
import { DefaultDataService, HttpUrlGenerator, QueryParams } from '@ngrx/data';
import { Group } from 'src/app/models/group.model';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@Injectable()
export class GroupDataService extends DefaultDataService<Group> {
constructor(http: HttpClient, httpUrl: HttpUrlGenerator) {
super('Group', http, httpUrl);
}
getWithQuery(params: QueryParams): Observable<any> {
return this.http.get<Group[]>('http://localhost:3000/api/groups?' + params)
.pipe(
map(data => {
const obj = {};
data.map(g => {
obj[g._id] = {
id: g._id,
name: g.name,
swearingAllowed: g.swearingAllowed,
creator: g.admin,
topic: g.topic
}
});
return Object.values(obj);
})
);
}
};