主页C++ Builder 资料C++ Builder 参考手册VCL 应用程序TFormatSettings
C++ Builder 串口控件
C++ Builder 编程技巧
C++ Builder 操作指南
C++ Builder 参考手册
基础知识
cfloat 浮点数
cmath 数学函数
cstdlib 标准库函数
System 字符串
System 日期和时间
System.Math.hpp 数学函数
其他数据类型
VCL 基础类
VCL 应用程序
 • TFormatSettings
   · 属性
   · 方法
 • FormatSettings
Pictures 图片
Graphics 绘图
Additional 控件
System 控件
A ~ Z 字母顺序排列的目录
网友留言/技术支持
TFormatSettings - 日期时间、货币、数字的格式
 • 简介 数据成员 方法
 • 用 TFormatSettings::Create 函数创建一个特定地区的格式信息
 • EraInfo 本地日历信息表
 • 用 FormatDateTime 函数显示或计算本地日历的年份
 • 用 Windows API 函数获取本地日历的年份
 • 自己计算本地日历的年份
 • 计算中国日历的年份,例如 2017 年 = 丁酉(鸡) 年

TFormatSettings 简介

TFormatSettings 是日期时间、货币、数字的格式,全局对象 FormatSettings 就是这个类型的。

 • 如果统一更改应用程序当前进程之内的日期时间、或者货币、数字的格式,需要用全局对象 FormatSettings
 • 如果给某个函数临时使用,或者应用程序里面维护几套不同的格式,可以创建与全局对象的数据不同的 TFormatSettings 对象。
 • 格式涉及到的控制符请参考 FormatDateTime 函数说明里面的 “格式控制符” 表格。

属性方法事件

 

头文件:

#include <System.SysUtils.hpp> (XE2 之后),#include <SysUtils.hpp> (XE 之前)

 

命名空间:

System::Sysutils

继承关系:

 

例:用 TFormatSettings::Create 函数创建一个特定地区的格式信息

LCID lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
TFormatSettings fs = TFormatSettings::Create(lcid);            // 创建一个格式信息 fs

如果按照上面的方法创建 fs,则不包含那个地区的 EraInfo 本地日历信息,一般用途足够了。
经过测试,TFormatSettings::Create 方法是通过当前线程的地区和语言获取的 EraInfo 本地日历信息,如下代码:

LCID lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
LCID lcidOld = GetThreadLocale();                              // 获取当前线程的地区和语言
SetThreadLocale(lcid);                                         // 修改当前线程的地区和语言
TFormatSettings fs = TFormatSettings::Create(lcid);            // 创建一个格式信息 fs
SetThreadLocale(lcidOld);                                      // 恢复当前线程的地区和语言

创建 fs 之后,就可以立即恢复线程的地区和语言了,只要 fs 对象不被修改和销毁,会一直维持获取的地区和语言信息。

通过继续的测试,即便是 fs 没有丢失数据,也没有被销毁,但是 FormatDateTime 函数始终依照 GetThreadLocale 获取到的信息,而不是依照参数 fs 来生成 era 信息。通过查看源码,发现 FormatDateTime 的 era 信息是通过 Windows API 函数 GetDateFormat(GetThreadLocale(), DATE_USE_ALT_CALENDAR, st, fmt, str, cchstr); 来实现的,并没有处理 fs 信息。GetDateFormat 的第一个参数始终用的是 GetThreadLocale()。

所以,只有当需要获取 EraInfo 本地日历信息的时候,才需要更改线程的地区和语言信息,否则使用第一段代码就足够了。

 

EraInfo 本地日历信息表:

EraInfo 为本地日历信息表,如果本地有和西元/公元不同的日历,会反映在这个列表里面。

有关 era 的描述,可以参考维基百科的 Calendar era 这篇文章,链接请点击:https://en.wikipedia.org/wiki/Calendar_era

TFormatSettings::TEraInfo 类型的定义:

struct TEraInfo
{
public:
  UnicodeString EraName;
  int EraOffset;
  TDate EraStart;
  TDate EraEnd;
};

数据 类型 描述
public:    
EraName UnicodeString 日历的纪元名称,例如:L"平成"、L"昭和"、L"단기"
EraOffset int 日历开始纪元的年,例如 1989, 1926, 2333
EraStart TDate 日历的日期范围:开始日期,经过测试,发现日本和韩国有 EraInfo,这个数值都是 0
EraEnd TDate 日历的日期范围:结束日期,经过测试,发现日本和韩国有 EraInfo,这个数值都是 0

在日本,EraOffset 和 GetEraYearOffset(L"平成") 返回的是 1989,GetEraYearOffset(L"昭和") 返回的是 1926;
在韩国,EraOffset 和 GetEraYearOffset(L"단기") 返回的是 2333,按理说단군기원是西元前 2333 年,可是没有通过符号反映出来;
经过测试,通过 Windows API 函数 EnumCalendarInfo 获取的数值,仍然是没有符号的,这说明这个值作为计算依据是有问题的。

实际测试,FormatDateTime 函数返回的 era 年代是对的,通过查看源码,发现 FormatDateTime 的 era 信息是通过 Windows API 函数 GetDateFormat(GetThreadLocale(), DATE_USE_ALT_CALENDAR, st, fmt, str, cchstr); 来实现的,并没有处理 FormatSettings 信息,即使给了这个参数。GetDateFormat 的第一个参数始终用的是 GetThreadLocale()。

 

用 FormatDateTime 函数显示或计算本地日历的年份

利用 FormatDateTime 可以得到本地日历的年份。FormatDateTime 函数始终使用 GetThreadLocale() 获取线程的地区和语言用作 era 本地日历,而不会去使用函数的 FormatSettings 参数。

格式 L"g" 和 L"gg" 是获取纪元名称的,例如 L"平成",L"단기"
格式 L"e", L"ee" 和 L"eeee" 是获取纪元年代的,是整数值,超过 2 位的年需要用 L"eeee",而 L"e" 和 L"ee" 只获取到最多 2 位的年。

例如:在韩国,2017 年是 “단기4350”

dt = TDateTime(2017, 7, 6);
s = FormatDateTime(L"ggee", dt);
和 s = FormatDateTime(L"ggeeee", dt);
分别得到 L"단기50" 和 L"단기4350"

例如:在日本,2017 年是 “平成29”

dt = TDateTime(2017, 7, 6);
s = FormatDateTime(L"ge", dt);
和 s = FormatDateTime(L"ggeeee", dt);
都将得到 L"平成29"

 

用 Windows API 函数获取本地日历的年份

void __fastcall TForm1::Button4Click(TObject *Sender)
{
  SYSTEMTIME st;
  memset(&st, 0, sizeof(st));
  st.wYear = 2017;  st.wMonth = 7;  st.wDay = 6; // 2017年7月6日

  LCID lcid;
  wchar_t buf[32];

  lcid = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); // 韩国
  GetDateFormat(lcid, DATE_USE_ALT_CALENDAR, &st, L"ggyyyy", buf, 32);
  Memo1->Lines->Add(buf);

  lcid = MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN); // 日本
  GetDateFormat(lcid, DATE_USE_ALT_CALENDAR, &st, L"ggyyyy", buf, 32);
  Memo1->Lines->Add(buf);
}

运行结果:

단기4350
平成29

 

自己计算本地日历的年份

开始纪元的年代在西元前的计算区别:

西元 n 年开始纪元的,按照现在的日期计算,那个日历纪元的年 = 西元年 - n + 1 年,例如 2017 年是平成 29 年,2017 - 1989 + 1 = 29;
西元前 n 年开始纪元的,按照现在的日期计算,那个日历纪元的年 = 西元年 + n 年,例如 2017 年是단기 4350 年,2017 + 2333 = 4350。

西元年 西元前3年 西元前2年 西元前1年 西元元年,西元0001年 西元0002年 西元0003年 西元xxxx年
    开始纪元 (元年) 第 2 年 第 3 年 第 4 年 第 5 年 第 xxxx+2 年

 

计算中国日历的年份,例如 2017 年 = 丁酉(鸡) 年

黄帝历是从西元前 2697 年开始纪元的,EraOffset 就是 2697,西元 2017 年相当于黄帝纪元 4714 年 (2017 + 2697 = 4714),
道历纪元与黄帝纪元相同,也是西元前 2697 年开始纪元的。

目前大多数人认为中国日历是从西元前 2697 年开始计算的,也有人认为是从西元前 2637 年开始的,他们之间差距 60 年,是干支纪年的一个循环周期。由于古代历法一直使用干支纪年,很少提及开始纪元的年代,所以根据古代的记载推算开始纪元的年代差一个周期甚至 n 个周期 (差 60 或 n 个 60 年) 也很容易理解。无论用哪个数据,计算出来的干支纪年的结果都是一样的。

有关 era 和中国日历的描述,可以参考维基百科的 Calendar era 这篇文章,链接请点击:https://en.wikipedia.org/wiki/Calendar_era
维基百科里面有关中国日历的另一篇文章 Chinese calendar,链接请点击:https://en.wikipedia.org/wiki/Chinese_calendar

中国日历最常用的是甲子、乙丑……这样的干支纪年方法,是从黄帝历纪元开始计算的,1年=甲子(鼠)年,2年=乙丑(牛)年……,具体计算方法:

  1 2 3 4 5 6 7 8 9 10 (整除无余数)
天干 = 黄帝纪元 % 10 (除以10的余数)

  1 2 3 4 5 6 7 8 9 10 11 12 (整除无余数)
地支 = 黄帝纪元 % 12 (除以12的余数)
生肖 = 与地支对应


2017 年 → 加上 2697 = 黄帝纪元 4714 年
  → 4714 % 10 = 4,即第 4 个天干 = 丁
  → 4714 % 12 = 10,即第 10 个地支(生肖) = 酉(鸡)
  → 2017 年为丁酉(鸡) 年

下一页:FormatSettings

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号