随笔 - 809  文章 - 0 评论 - 144 阅读 - 770万

封装成了一个TFastDateTime类,

2013-03-12 补充 暂时用自动修改用户电脑的日期格式的方法

-------------------------------------------------------------------------------

Delphi中StrToDateTime函数TFormatSettings参数的使用

复制代码
var
  FSetting : TFormatSettings;
  DateTime1: tDateTime;
begin
  FSetting := TFormatSettings.Create(LOCALE_USER_DEFAULT);
  FSetting.ShortDateFormat:='yyyy-MM-dd';
  FSetting.DateSeparator:='-';
  //FSetting.TimeSeparator:=':';
  FSetting.LongTimeFormat:='hh:mm:ss.zzz';
  DateTime1 := StrToDateTime('2011-10-20 15:59:59:789', FSetting);
end;
复制代码

上例中的代码经过测试,加入FSetting.TimeSeparator:=':';后,毫秒部分读取失败,原因不太清楚。

TFormatSettings中一些属性的解释:

DateSeparator :Char

日期分隔符,用于分隔年月日
TimeSeparator :Char
时间分隔符,用于分隔小时,分钟,秒
ShortDateFormat:String
区域设置中短日期格式的定义。
LongDateFormat :String
区域设置中长日期格式的定义。
ShortTimeFormat:String
区域设置中短时间格式的定义。
LongTimeFormat :String
区域设置中长时间格式的定义。
TimeAMString :String
用来表示上午的字符串
TimePMString :String
用来表示下午的字符串
ShortMonthNames:array[1..12] of String;
用于缩略表示月份名称的数组,就是在使用FormatDateTime时显示的mmm标识的字符串
LongMonthNames:array[1..12] of String;
用于完整表示月份名称的数组,就是在使用FormatDateTime时显示的mmmm标识的字符串
ShortDayNames :array[1..7] of String;
用于缩略表示星期名称的数组,就是在使用FormatDateTime时显示的ddd标识的字符串
LongDayNames :array[1..7] of String;
用于完整表示星期名称的数组,就是在使用FormatDateTime时显示的ddd标识的字符串
TwoDigitYearCenturyWindow:Word = 50;
在使用两位年份时的起始年份。

----------------------------------------------------------------------------------------------------

 

strtodatetime 这个函数在win7下出错

例如 strtodatetime('2010-11-25') 在win7下出错 , 但在xp系统下正常
解决方法
日期格式不一样,你需要统一日期格式,可以再控制面板中修改,或者用代码实现
Delphi(Pascal) code

复制代码
var
settings: TFormatSettings;
dt: TDateTime;
begin

GetLocaleFormatSettings(GetUserDefaultLCID, settings);
settings.DateSeparator := '-';
settings.TimeSeparator := ':';
settings.ShortDateFormat := 'yyyy-mm-dd';
settings.ShortTimeFormat := 'hh:mm:ss';

dt:= strToDateTime('2010-3-19 08:09:10',settings);

end; 
复制代码


----------------------------------------

 

复制代码
我也遇到过.
主要原因是不同的系统可能日期分隔符号等不同,需要你在软件中设置
给楼主的意见是你的软件每次运行时都先设置一下.
procedure SetLocDateFormat;
begin
    //设置本机日期格式。
    SetLocaleInfo(LOCALE_SYSTEM_DEFAULT,LOCALE_SSHORTDATE,PChar('yyyy-MM-dd'));
end;

我的所有软件在初始化时都先调用这个过程,统一了日期格式后,就不会有问题喽.
再试试strtodate('2011-02-10')看有木有问题
----------------------------------------------
你我,都可以是个造梦者! 
复制代码
如果4楼给我这样的软件,我绝对不会在我的电脑上使用,除非没有同类软件可用。
为什么?
很简单,因为你的软件干嘛要动我使用习惯?
当然,你可以说,动一下没什么,又不会死。

我的观点就是:所有你的功能在你的代码里面实现,少去改变别人的习惯和使用环境。尊重别人的使用习惯也是一个编程技巧。

 

 =====================================2013-03-12补充=============================================

 

复制代码
//转换函数
function ChangeDateTime(sTime:String):TDateTime;
var
  settings: TFormatSettings;
  dt: TDateTime;
begin
  GetLocaleFormatSettings(GetUserDefaultLCID, settings);
  settings.DateSeparator := '-';
  settings.TimeSeparator := ':';
  settings.ShortDateFormat := 'yyyy-mm-dd';
  settings.ShortTimeFormat := 'hh:nn:ss';
  ChangeDateTime:= strToDateTime(sTime,settings);
end;

//测试用例
procedure TForm1.Button1Click(Sender: TObject);
begin
  DateTimePicker1.DateTime:=ChangeDateTime('2010-11-25');
end;
复制代码

 

或:

复制代码
var  
  settings: TFormatSettings;
  dt: TDateTime;
begin

  GetLocaleFormatSettings(GetUserDefaultLCID, settings);
  settings.DateSeparator := '-';
  settings.TimeSeparator := ':';
  settings.ShortDateFormat := 'yyyy-mm-dd';
  settings.ShortTimeFormat := 'hh:nn:ss';

  dt:= strToDateTime('2010-3-19 08:09:10',settings);

end;
复制代码

------------

 

复制代码
 让delphi程序不受WINDOWS日期格式的影响

如果WINDOWS系统的短日期格式为“yyyy/m/d”,执行下面的代码会报错:2013-01-29 00:00:00不是合法的日期
procedure TFrmQuerySale.FormShow(Sender: TObject);
var
sDate: string;
begin
inherited;
// 默认查当天的销售数据
sDate := FormatDateTime('yyyy-mm-dd', Now);
DateTimePicker1.DateTime := StrToDateTime(sDate + ' 00:00:00');
DateTimePicker2.DateTime := StrToDateTime(sDate + ' 23:59:59');
Find(Trim(edtBillId.Text), DateTimePicker1.DateTime, DateTimePicker2.DateTime);
edtBillId.SetFocus;
end;

如何解决?
procedure TdmCommonFun.SetSysDateFormat;
begin
// 设置WINDOWS系统的短日期的格式
SetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, 'yyyy-MM-dd');

Application.UpdateFormatSettings := False;
// 设定程序本身所使用的日期时间格式
LongDateFormat := 'yyyy-MM-dd';
ShortDateFormat := 'yyyy-MM-dd';
LongTimeFormat := 'hh:nn:ss';
ShortTimeFormat := 'hh:nn:ss';
DateSeparator := '-';
TimeSeparator := ':';
end;
在程序初始化的时候执行上面的代码,不论WINDOWS的短日期格式怎样设置都不再影响
DELPHI程序。
复制代码

 

 

Delphi的strToDate函数在Win7下转换问题
2012-03-23         作者:李海彬   阅读:975

       以前编写的一些程序,在Windows Vista及Win 7下运行时,发现strToDate日期格式转换的问题,仔细的分析了一下,XP默认的日期格式用‘-'分隔,如1990-12-10,而Vista之后 用‘/’分隔,如1990/12/10,使用strtoDate('1990-12-10')将字符串类型的日期转成TDate日期时,在Vista和 Win7下提示错误。试着将win7的短日期格式改成'yyyy-mm-dd',此时程序运行正常,但是修改win7系统的短日期格式并不是一个好的办 法,因为其它的程序可能需要用到'yyyy/mm/dd'的短格式,上网去查了一下,大致也是这样,说是strToDate及strToDateTime 函数存在这样的问题,解决的方法是先将'/'转成'-'之类的。
      是strToDate函数只支持'yyyy-mm-dd'格式的日期字符串吗?在Xp环境下,试着将短日期格式修改成'yyyy/mm/dd'的格式,之 后执行strtoDate('1990-12-10')作日期类型转换,发现同样的提示错误,而此时使用strtoDate('1990/12/10') 却成功转换了,也就是说strToDate函数在作日期转换时,并不是支持'yyyy-mm-dd'格式,而是按系统的短日期格式对日期字符串进行区分.

 


 执行以下代码:
 st:='2010-01-12';
 date1.date:= strtodate(st);
 弹出错误提示:

 

 

而如果程序改变为:

 

st:='2010/01/12';
 date1.date:= strtodate(st);

 

 

按下"转换"按钮,此时执行成功了,从这里我们可以知道,strTodate函数在将字符串转成日期格式时,是根据系统的短日期,而不是 'yyyy-mm-dd'这种格式,但这样就给我们作转换带来了麻烦,因为在作转换时,只有两种方法,一是将系统的短日期强行转成'yyyy-mm-dd 的格式,如下指令:

 

setLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,PCHAR('yyyy-MM-dd'));
sendMessageTimeOut(HWND_BROADCAST,WM_SETTINGCHANGE,0,0,SMTO_ABORTIFHUNG,10,P);

 

这样你电脑的短日期将转成'yyyy-mm-dd',另一种方法是先得到系统的短日期格式,再将自己的日期字符串的格式设成与系统短日期一致,后一种方法将要编写更多的代码来完成转换。

---------------------------------------------

暂时 用这个方法 来解决了

复制代码
delphi调用strtodatetime时遇到日期格式错误,但是检查了字符串后发现为'2000-01-01'并没有问题。

 

同事提示我去看一下控制面板里的 区域和语言选项 里, 发现果然短日期分隔符为 / ,则日期解析的格式变成 2000/01/01,显然之前的字符串会出现问题.

 

于是查找资料,发现有关于此问题的windows API:

 

int GetLocaleInfo(
    LCID Locale, // locale identifier ,设置信息的范围,是系统级,还是当前用户
    LCTYPE LCType, // type of information,设置信息的类型
    LPTSTR lpLCData, // address of buffer for information,设置成的值,必须用 pchar的格式传进去
    int cchData  // size of buffer
   );

BOOL SetLocaleInfo(
    LCID Locale, // locale identifier,同上
    LCTYPE LCType, // type of information to set
    LPCTSTR lpLCData  // pointer to information to set
   );

 

两个函数的参数很类似,其中 Locale可以取两个值:LOCALE_SYSTEM_DEFAULT,表示要操作的是系统默认的设置; LOCALE_USER_DEFAULT,表示要操作的是当前用户的设置。还可以取其他值,用于具体修改某种语言区域的设置。一般取 LOCALE_USER_DEFAULT。
LCType,表示要操作信息的类型,也就是要操作的是哪一种设置。可用的值有很多:
LOCALE_SSHORTDATE :短日期格式
LOCALE_SLONGDATE :长日期格式
LOCALE_STIMEFORMAT:时间格式
另外 LOCALE_STIME 表示时间分隔符,LOCALE_SDATE 表示日期分隔符。可以单独使用,也可以在使用 LOCALE_SSHORTDATE 和 LOCALE_STIMEFORMAT 的同时一并修改,所以不需要单独操作。
使用GetLocaleInfo或SetLocaleInfo时,每次只能操作一个类型。比如要同时设置短日期格式、长日期格式、时间格式,就必须分别用三个类型代号调用三次 SetLocaleInfo。

在程序启动时执行此函数:

function GetDateTimeFormat():string;
var
  buf:pchar;
  i:integer;
  GPrevShortDate,GPrevLongDate,GPrevTimeFormat:string;
begin
  getmem(buf,20);
  i:=20; //i必须在调用前赋值为buf缓冲区的长度。如果设为0或负值,将取不到设置的值
  GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,buf,i); //取当前用户设置,短日期格式。
  GPrevShortDate:=string(buf);
  FreeMem(buf);
  result := GPrevShortDate;
end;

 

程序结束时执行此函数:

procedure SetDateTimeFormat(aParam:string);
var
  p:DWORD;
begin
  SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,pchar(aParam)); //设置短日期格式
  SendMessageTimeOut(HWND_BROADCAST,WM_SETTINGCHANGE,0,0,SMTO_ABORTIFHUNG,10,p);//设置完成后必须调用,通知其他程序格式已经更改,否则即使是程序自身也不能使用新设置的格式
end;

 

需要设置一全局变量保存启动时获取的日期格式.并在结束时恢复此格式.
复制代码

------------------

【Delphi获取与设置系统时间格式(长日期与短日期)】

Delphi获得与设置系统时间格式

在 Delphi中,特别是在写管理系统软件时,经常要用到 FormatDateTime 以将 TDateTime 格式的日期时间转换成字符串形式的值显示或保存起来,或者用 StrToDateTime将字符串形式的日期时间转换成 TDateTime 然后再做其他操作。
在进行时间或日期的转换时,会使用系统当前设定的时间日期格式。而如果时间日期格式与字符串中的表示方式不相符,会使转换过程 失败。例如当前短日期格式设定为'yyyy/MM/dd',而要转为 '2006-10-20'这样的字符串为日期,就会报错,说这不是一个有效的日期。
所以在进行转换前,要确保系统的日期时间格式与程序中使用的相符。一种方法是在安装时由安装程序设置,或者明确告诉用户必须设置成要求格式。另一种就是程序在启动时,自动设定为需要的格式,退出程序时再恢复原来的设置。


需要用到的有两个Windows API,一个是 GetLocaleInfo,一个是 SetLocaleInfo

查API说明:
int GetLocaleInfo(
LCID Locale, // locale identifier ,设置信息的范围,是系统级,还是当前用户
LCTYPE LCType, // type of information,设置信息的类型
LPTSTR lpLCData, // address of buffer for information,设置成的值,必须用 pchar的格式传进去
int cchData // size of buffer
);

BOOL SetLocaleInfo(
LCID Locale, // locale identifier,同上
LCTYPE LCType, // type of information to set
LPCTSTR lpLCData // pointer to information to set
);

两 个函数的参数很类似,其中 Locale可以取两个值:LOCALE_SYSTEM_DEFAULT,表示要操作的是系统默认的设置; LOCALE_USER_DEFAULT,表示要操作的是当前用户的设置。还可以取其他值,用于具体修改某种语言区域的设置。一般取 LOCALE_USER_DEFAULT。
LCType,表示要操作信息的类型,也就是要操作的是哪一种设置。可用的值有很多,Delphi的联机帮助,或者查MSDN,都有一个大列表。但跟日期时间格式相关的一共有这几个:
LOCALE_SSHORTDATE :短日期格式
LOCALE_SLONGDATE :长日期格式
LOCALE_STIMEFORMAT:时间格式
另外 LOCALE_STIME 表示时间分隔符,LOCALE_SDATE 表示日期分隔符。可以单独使用,也可以在使用 LOCALE_SSHORTDATE 和 LOCALE_STIMEFORMAT 的同时一并修改,所以不需要单独操作。
使用GetLocaleInfo或SetLocaleInfo时,每次只能操作一个类型。比如要同时设置短日期格式、长日期格式、时间格式,就必须分别用三个类型代号调用三次 SetLocaleInfo。
还要一个要注意的问题是,设置日期时间格式后,应该向当前系统的激活窗口广播发送 WM_SETTINGCHANGE 消息,否则即使修改了,程序里还是不能用的。
以下是获取和设置的程序片断。

1.//获取时间日期格式

procedure GetDateTimeFormat();
var
buf:pchar;
i:integer;
GPrevShortDate,GPrevLongDate,GPrevTimeFormat:string;
begin
getmem(buf,100);
i:=100; //i必须在调用前赋值为buf缓冲区的长度。如果设为0或负值,将取不到设置的值
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,buf,i); //取当前用户设置,短日期格式。
GPrevShortDate:=string(buf);
i:=100;
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SLONGDATE,buf,i); //取长日期格式
GPrevLongDate:=string(buf);
i:=100;
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,buf,i); //取时间格式
GPrevTimeFormat:=string(buf);
FreeMem(buf);
end;
2.//设置时间格式

procedure SetDateTimeFormat();
var
p:DWORD;
begin
   SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,pchar('yyyy-MM-dd')); //短日期
   SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SLONGDATE,pchar('yyyy''年''M''月 ''d''日'''));
   SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,pchar('H:mm:ss')); //设置时间     
SendMessageTimeOut(HWND_BROADCAST,WM_SETTINGCHANGE,0,0,SMTO_ABORTIFHUNG,10,p);
//设置完成后必须调用,通知其他程序格式已经更改,否则即使是程序自身也不能使用新设置的格式
end;

在程序初始化时调用GetDateTimeFormat,将取出的设置保存起来,然后用SetDateTimeFormat设置需要的格式。在程序退出时再次调用SetDateTimeFormat将保存的值写回去。
当然,如果程序已经在运行,别的程序也象我们这样把格式改成它需要的格式,那就没办法了,同时就只能运行一个,否则会互相干扰。如果一定要想办法的话,或许可以处理 WM_SETTINGCHANGE 消息,再把改掉的改回来?有点强盗。

----------------------------------------------------------------

动态设置系统日期格式【转】

1 问题提出
在操作数据库表的时候,通常需要对表中的日期类型的数据做处理,对于系统来说存在多种
日期格式,数据库的日期字段也存在多种格式,当往数据库表中插入日期字段的时候必须两者的日期
格式匹配才能插入数据,在这种情况下,一般需要更改系统的日期格式,改成与数据库表中的日期字段
一致的格式(因为表的设计已经定好,对于日期的格式也已经唯一确定,所以一般情况下都是更改系统
的日期格式),那么就必须能够在程序中自动改变系统的日期格式,使其和表的日期格式匹配!
2 程序中修改日期格式的系统API的说明
主要需要使用下面的windows API
BOOL SetLocaleInfo(
LCID Locale, // locale identifier
LCTYPE LCType, // type of information to set
LPCTSTR lpLCData // pointer to information to set
);
本函数主要用于windows系统中设置系统的区域选项,主要包括时间,语言等选项的设置。
LCID:locale identifier (区域标志)
在系统中有两个默认值:
LOCALE_SYSTEM_DEFAULT:系统默认的区域选项;
LOCALE_USER_DEFAULT:当前用户的区域选项;
同时用户也可以通过 MAKELCID宏动态创建LCID;
LCType:需要设定的系统信息类型;
主要包括下面的值:(对于以下值的中文解释见下篇文章)
LOCALE_ICALENDARTYPE LOCALE_SDATE
LOCALE_ICURRDIGITS LOCALE_SDECIMAL
LOCALE_ICURRENCY LOCALE_SGROUPING
LOCALE_IDIGITS LOCALE_SLIST
LOCALE_IFIRSTDAYOFWEEK LOCALE_SLONGDATE
LOCALE_IFIRSTWEEKOFYEAR LOCALE_SMONDECIMALSEP
LOCALE_ILZERO LOCALE_SMONGROUPING
LOCALE_IMEASURE LOCALE_SMONTHOUSANDSEP
LOCALE_INEGCURR LOCALE_SNEGATIVESIGN
LOCALE_INEGNUMBER LOCALE_SPOSITIVESIGN
LOCALE_ITIME LOCALE_SSHORTDATE
LOCALE_S1159 LOCALE_STHOUSAND
LOCALE_S2359 LOCALE_STIME
LOCALE_SCURRENCY LOCALE_STIMEFORMAT
lpLCData:需要设定的信息的存放地址;
与起对应的函数为
int GetLocaleInfo(

LCID Locale, // locale identifier
LCTYPE LCType, // type of information
LPTSTR lpLCData, // address of buffer for information
int cchData // size of buffer
);
主要用于取得当前系统的区域设置,举例:

用api修改区域选项中时间格式,短日期yyyy-m-d改成长日期yyyy-mm-dd
SetLocaleInfo(LOCALE_USER_DEFAULT,   LOCALE_SSHORTDATE,   "yyyy-MM-dd");

下面再提供一个Delphi对该问题的处理方法,大家可以做个参照
1.//获取时间日期格式
       buf:pchar;
       i:integer;
       GPrevShortDate,GPrevLongDate,GPrevTimeFormat:string;

       getmem(buf,100);
       i:=100; //i必须在调用前赋值为buf缓冲区的长度。如果设为0或负值,将取不到设置的值
       GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,buf,i); //取当前用户设置,短日期格式。
       GPrevShortDate:=string(buf);
       i:=100;
       GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SLONGDATE,buf,i); //取长日期格式
       GPrevLongDate:=string(buf);
       i:=100;
       GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,buf,i); //取时间格式                
       GPrevTimeFormat:=string(buf);
       FreeMem(buf);

2.//设置时间格式
       p:DWORD;
       SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,pchar('yyyy-MM-dd')); //设置短日期格式
       SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SLONGDATE,pchar('yyyy''年''M''月 ''d''日'')); //设置长日期格式为 yyyy'年'M'月'd'日',“年月日”字符必须用单引号括起来。Delphi字符串里必须用两个单引号。
       SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,pchar('H:mm:ss')); //设置时间格式,24小时制
       SendMessageTimeOut(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_ABORTIFHUNG, 10, p); //设置完成后必须调用,通知其他程序格式已经更改,否则即使是程序自身也不能使用新设置的格式

 

 ===============================

我封装的保存下:

复制代码
{
  2012.06.26-----创建
}

unit UFastDateTimeApi;

interface

uses
  System.SysUtils, System.Classes, Winapi.Windows, Winapi.Messages;

type TFastDateTimeApi = class
  public
    //自动修改客户电脑的日期时间格式兼容win7,win8,xp
    procedure AutoEditUserComputerDateFormat;
  end;

implementation

procedure TFastDateTimeApi.AutoEditUserComputerDateFormat;
var
  p: DWORD;
begin
  SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,pchar('yyyy-MM-dd')); //短日期注意MM必须大写
  SetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,pchar('H:mm:ss')); //设置时间
  //设置完成后必须调用,通知其他程序格式已经更改,否则即使是程序自身也不能使用新设置的格式
  SendMessageTimeOut(HWND_BROADCAST,WM_SETTINGCHANGE,0,0,SMTO_ABORTIFHUNG,10,p);
end;

end.
复制代码

 

posted on   del88  阅读(25)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示