将八位数字转换为日期的最有效方法是什么?

3

我正在使用 ColdFusion 9.0.1 和一些不可更改的数据库。

我正在访问一个将日期存储为八位数字且没有小数位的数据库,如下所示:

YYYYMMDD

我需要能够读取日期,对日期进行加减操作,并创建新日期。我正在寻找一种冷酷的解决方案,以高效地(不需要很多代码)将日期转换为我们的标准格式,即

MM/DD/YYYY

然后将其转换回数据库的格式以进行保存。

我需要编写代码,使非ColdFusion程序员可以轻松阅读、使用、复制和修改它,以用于其他功能(例如添加一天到日期)。因此,我不是寻找最少量的代码,而是高效且易读的代码。

您能否建议任何可以使此代码块更灵活、易读或更有效(代码更少)的内容?

<cfscript>

// FORMAT DB DATE FOR BROWSER
DateFromDB = "20111116";
DatedToBrowser = createBrowserDate(DateFromDB);
writeOutput(DatedToBrowser);

function createBrowserDate(ThisDate) {
    ThisYear = left(ThisDate, 4); 
    ThisMonth = mid(ThisDate, 4, 2);
    ThisDay = right(ThisDate, 2);
    NewDate = createDate(ThisYear, ThisMonth, ThisDay);
    NewDate = dateFormat(NewDate, "MM/DD/YYYY");
    return NewDate;
}

// FORMAT BROWSER DATE FOR DB
DateFromBrowser = "11/16/2011";
DateToDB = createDBDate(DateFromBrowser);
writeDump(DateToDB);

function createDBDate(ThisDate) {
    ThisYear = year(ThisDate); 
    ThisMonth = month(ThisDate);
    ThisDay = day(ThisDate);
    NewDate = "#ThisYear##ThisMonth##ThisDay#";
    return NewDate;
}

</cfscript>

1
我认为现在它已经相当易读了,只是不要忘记在那些函数中声明变量。 - Henry
在这里挑剔一下...我会将NewDate = "#ThisYear##ThisMonth##ThisDay#"更改为NewDate = ThisYear&ThisMonth&ThisDay,但是我讨厌代码中多余的井号。此外,在第一个函数中,您可能可以摆脱createdate()和dateFormat(),并简单地返回thisMonth&“/”&Thisday&“/”&ThisYear; - Scott Stroz
实际上...再看一遍,你可以把createDBDate改成简单地返回dateFormat(ThisDate,"YYYYMMDD")。 - Scott Stroz
5个回答

7

首先找出曾经创建数据库的人并踢他的下面...

个人而言,我会使用sql进行转换,这样我的代码只涉及日期对象。

Select Convert(DateTime, Convert(VarChar(8),DateTimeInventedByIdjitColumn))
From SomeTable

作为我们同行所说,将日期存储为日期。

'08/06/2011' 可能是六月的第8天或者八月的第6天,这取决于所在地区。

20111643 是一个有效的整数。

不使用正确的日期类型只会导致大量功能和漏洞,最好还是避免。


1
好观点!虽然这不是问题所要求的。由于DB日期格式为YYYYMMDD,因此至少可以进行排序,而YYYYDDMM在其他地方很少使用,因此不容易被误解。 - Henry
1
如果你被迫使用字符串格式来表示日期,YYYYMMDD 是最好的选择,但这并不意味着日期应该以字符串形式存储。 - Peter Boughton
2
在SQL阶段进行转换绝对是一个好主意,比使用CFML函数更有意义,尽管我认为这里的示例代码假定了MS SQL Server?这一点很重要,因为不同的平台具有不同的转换函数,我们不知道OP正在使用哪个。 - Peter Boughton
手腕受到 SQL 语法的严厉惩罚,从现在起我要提一下我使用的是哪种。我们倾向于使用 YYYY-MM-DD,这同样是普遍适用的。不能使用 int,当溢出时不具备未来的可扩展性(咧嘴笑)。 - Tony Hopkinson
Peter,你说得非常好。我请求ColdFusion解决方案的原因是因为我不知道正在使用哪个数据库。事实上,其他开发人员甚至也不知道。这有点像一个大谜团。我的工作是为这些小问题创建ColdFusion解决方案。 - Evik James
不使用适当的日期类型只是一堆功能和错误的集合,最好等待发生。这只是轻描淡写的说法。你无法想象我们为了让网站与数据库通信而必须跳过的障碍。几乎找不到任何一致性。感谢这个引用! - Evik James

5
您可以将每个函数重写为一行代码。
function createBrowserDate(ThisDate) {
  return mid(ThisDate,4,2) & "/" & right(ThisDate,2) & "/" & left(ThisDate,4);
}

并且

function createDBDate(ThisDate) {
  return dateFormat( ThisDate, "YYYYMMDD" );
}

我认为你可能为我的目的压缩了它太多,但这肯定是最易读且代码最少的。谢谢! - Evik James
这段代码可能是最简短的,但如果没有 createDate() 函数,你就会跳过验证。其次,ThisDate 在这里有两个不同的含义,因为第一个期望 YYYYMMDD 格式,而第二个期望一个日期对象。最后,只使用这两个函数无法真正使用 CF 内置的日期函数。 - Henry
1
首先,即使使用createDate()函数,如果传递给createBrowserDate()函数的值不是有效日期,则createDate()函数也会抛出错误,因此没有“验证”功能。其次,“ThisDate”在两个不同的函数中作为参数名称是否重复并不重要。最后,为什么不能使用任何内置日期函数呢? - Scott Stroz

3
不要将日期保存为字符串 - 保存日期为日期,需要时再进行格式化。
如果您无法更正数据库以使用实际的日期列(如果可以的话应该这样做),那么可以使用这两个函数将其转换为/from YYYYMMDD 和日期对象:
function parseYMD( YYYYMMDD )
{
    if ( ! refind('^\d{8}$' , Arguments.YYYYMMDD ) )
        throw "Invalid Format. Expected YYYYMMDD";

    return parseDateTime
        ( Arguments.YYYYMMDD.replaceAll('(?<=^\d{4})|(?=\d{2}$)','-') );
}

function formatYMD( DateObj )
{
    return DateFormat( DateObj , 'yyyymmdd' );
}

通过使用日期对象,任何开发者都可以使用内置函数(如DateAddDateCompare等)而无需关心格式化。

我可能会使用throw()而不是throw,这样我就可以抛出比“应用程序”更好的异常类型,但除此之外,我认为这是最好的答案。 - Adam Cameron
Peter,非常感谢你抽出时间回答我的问题。但是,我认为你没有仔细阅读我的问题。首先,我对数据库没有任何控制权。我不能更改它,也不能建议任何更改。其次,虽然你的代码可能完美执行,但它离“普通程序员”可读还有很长的路要走(无论这是什么)。谢谢! - Evik James
记录一下,我特意询问了与我合作的每个人对正则表达式的经验。没有人有任何经验。使用ColdFusion的最大好处是对于任何问题都有100种解决方案。谢谢您的回答! - Evik James

1

对于我来说,正则表达式不太易读,所以我不是正则表达式的粉丝。

既然您在使用CF9,我建议输入参数并指定函数返回类型,以便下一个接手代码的人更容易理解。

首先,在从数据库中读取日期后,我会使用parseDBDate()将其解析为日期对象。

Date function parseDBDate(required String dbDate)
{
    var yyyy = left(dbDate, 4); 
    var mm = mid(dbDate, 4, 2);
    var dd = right(dbDate, 2);

    return createDate(yyyy , mm, dd);
}

一旦您拥有日期对象,您可以使用所有内置的日期函数,例如DateAdd()DateDiff()

在需要显示日期之前,请调用browserDateFormat()

String function browserDateFormat(required Date date) 
{
    return dateFormat(date, "MM/DD/YYYY");
}

在持久化到数据库时,将 dBDateFormat()调用放在<cfqueryparam value="">中。

String function dBDateFormat(required Date date) 
{
    return dateFormat(date, "YYYYMMDD");
}

1
FWIW,我的正则表达式基本上是在第四位之后或倒数第二位之前插入一个连字符。一旦花点时间去理解它,正则表达式真的不难学习。 :) - Peter Boughton
谢谢提供信息!看起来你来自Java世界,是吗? - Evik James
有点吧。 :) 只是遵循CF的函数命名约定,使用parseXXX()XXXFormat() - Henry

0
一行代码 :)
myDateString = "20110203";

myCfDate = createObject("java","java.text.SimpleDateFormat").init("yyyyMMdd").parse(myDateString,createObject("java","java.text.ParsePosition").init(0*0));

如果您想解析不同的格式,请将"yyyyMMdd"更改为任何其他支持的格式。

http://download.oracle.com/javase/1.5.0/docs/api/java/text/SimpleDateFormat.html

ParsePosition 用于指定从哪里开始解析字符串。 0*0 是 JavaCast("int",0) 的简写 - 在 Adobe cf 引擎中,0 是一个字符串,直到你对它进行数学运算,然后它就变成了 Double,而 ParsePosition 构造函数支持 Double。技术上讲,它是用 int 构造的,但是 cf 足够聪明,可以将 Double 降级为 int。

http://download.oracle.com/javase/1.5.0/docs/api/java/text/ParsePosition.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接