Globalization versus DateTime.ParseExact

  • Thread starter Thread starter Cor Ligthert
  • Start date Start date
C

Cor Ligthert

Hello everybody,

Jay and Herfried are telling me every time when I use CDate that using the
datetime.parseexact is always the best way to do String to datetime
conversions. They don't tell why only that I have to listen to them because
they know it better.

They told also that in a business situation it is better to use
datetime.parseexact for changing cultures and not to use the globalization
setting. I did not give them this sample, only told the situation how that
in my opinion has to be done. Jay gave the business sample by the way in
another thread, where he told that using datetime.parseexact was the way to
go for that. However did in that thread as well not tell how and why it was
better, only that he, Herfried and a C# MVP were telling that and therefore
it was better.

I have made a little code example from it, to make it more showable, can
someone tell me how it can be done better using datetime.parseexact as Jay
and Herfried constantly are telling, and why that is better to use in this
kind of situations where the documents can come from all over the world.

Public Class test
Shared Sub main()
Dim d As New document
Dim o As New order
'The next is the setting from an XML file or whatever document
d.culture = "nl-NL"
d.deliverydate = "25 aug 2004"
d.orderdate = "10 juli 2004"
d.price = "? 111,10"
d.quantity = "10.000"
Dim thisErrors As Errors = ConvertDocumentToOrder(d, o)
'Do the debugprinting yourself
'This is another document
d.culture = "en-US"
d.deliverydate = "aug 25 2004"
d.orderdate = "july 10 2004"
d.price = "$ 111.10"
d.quantity = "10,000"
thisErrors = ConvertDocumentToOrder(d, o)
'Do the debugprinting yourself
End Sub
Public Shared Function ConvertDocumentToOrder(ByVal d As document, _
ByVal o As order) As Errors
Dim myError As New Errors
Try
Threading.Thread.CurrentThread.CurrentCulture = _
New Globalization.CultureInfo(d.culture)
o.orderdate = CDate(d.orderdate)
o.deliverydate = CDate(d.deliverydate)
o.price = CDec(d.price)
o.quantity = CInt(d.quantity)
o.culture = d.culture
Return myError
Catch ex As Exception 'However whatever error set
'evaluate(myerror, ex)
Return myError
Finally
Threading.Thread.CurrentThread.CurrentCulture = _
Globalization.CultureInfo.InstalledUICulture
End Try
End Function
End Class
Public Class document
Public orderdate As String
Public deliverydate As String
Public quantity As String
Public price As String
Public culture As String
End Class
Public Class order 'Normally with properties where validation is used
Public orderdate As DateTime
Public deliverydate As DateTime
Public quantity As Integer
Public price As Decimal
Public culture As String
End Class
Public Class Errors
Public whatever As String
Public Sub New()
whatever = ""
End Sub
End Class

With what I don't say that there can be probably situations where
datetime.parseexact are simpler to use, however that in my opinion when you
know exactly the format of the string(s), that will be used in the document.
 
Cor Ligthert said:
Public Class test
Shared Sub main()
Dim d As New document
Dim o As New order
'The next is the setting from an XML file or whatever document
d.culture = "nl-NL"
d.deliverydate = "25 aug 2004"
d.orderdate = "10 juli 2004"
d.price = "? 111,10"
d.quantity = "10.000"
Dim thisErrors As Errors = ConvertDocumentToOrder(d, o)
'Do the debugprinting yourself
'This is another document
d.culture = "en-US"
d.deliverydate = "aug 25 2004"
d.orderdate = "july 10 2004"
d.price = "$ 111.10"
d.quantity = "10,000"
thisErrors = ConvertDocumentToOrder(d, o)
'Do the debugprinting yourself
End Sub
Public Shared Function ConvertDocumentToOrder(ByVal d As document, _
ByVal o As order) As Errors
Dim myError As New Errors
Try
Threading.Thread.CurrentThread.CurrentCulture = _
New Globalization.CultureInfo(d.culture)
o.orderdate = CDate(d.orderdate)
o.deliverydate = CDate(d.deliverydate)
o.price = CDec(d.price)
o.quantity = CInt(d.quantity)
o.culture = d.culture
Return myError
Catch ex As Exception 'However whatever error set
'evaluate(myerror, ex)
Return myError
Finally
Threading.Thread.CurrentThread.CurrentCulture = _
Globalization.CultureInfo.InstalledUICulture

Same bug. This will not necessarily reset the culture to the culture used
before.

Instead of using 'CDate' and changing the culture, I would use
'DateTime.Parse' (= 'Date.Parse') and specify the 'DateTimeInfo':

\\\
.... = Date.Parse(d.DiliveryDate, ci.DateTimeFormat)
///

.... 'ci' is your custom culture info with the custom date/time format set.
 
Instead of using 'CDate' and changing the culture, I would use
'DateTime.Parse' (= 'Date.Parse') and specify the 'DateTimeInfo':

\\\
... = Date.Parse(d.DiliveryDate, ci.DateTimeFormat)
///
This is this newsgroup almost full of, I asked why, what is the benefit, I
see only more to type words?

And what about all the other culture depending values?

Cor
 
Cor Ligthert said:
This is this newsgroup almost full of, I asked why, what is the benefit, I
see only more to type words?

And what about all the other culture depending values?

Most 'Parse' methods expect a format information, for example
'Int32.Parse'...
 
Cor,
Jay and Herfried are telling me every time when I use CDate that using the
datetime.parseexact is always the best way to do String to datetime
Ah! There's the rub, you are talking Oranges; Herfried, Jon & I are talking
Apples! :-)

The Oranges:

Actually in Your Example I would use DateTime.Parse:

Instead of:
Threading.Thread.CurrentThread.CurrentCulture = _
New Globalization.CultureInfo(d.culture)
o.orderdate = CDate(d.orderdate)
o.deliverydate = CDate(d.deliverydate)

I would use:
Dim culture As New Globalization.CultureInfo(d.culture)

o.orderdate = DateTime.Parse(d.orderdate, culture)
o.deliverydate = DateTime.Parse(d.deliverydate, culture)

Notice that I am simply passing the culture required in the above, rather
then relying on the "global variable" CurrentCulture. By passing the cutlure
as a parameter, I don't need a Try/Finally to restore the "global variable"
CurrentCulture. Also I do not risk changing the "global variable"
CurrentCulture that routines that ConvertDocumentToOrder may call require
set in a specific way. Yes you want it changed for CDate, however you may
not want it changed for CDec or CInt! For example changing the decimal
separator from a comma to a period. Plus you may call one of your own
routines (or team's routines) that requires the CurrentCulture to be a
specific value.

I hope you agree tracking down problems with "global variables" in a program
can be very difficult, especially when they are being set & reset all over
the program, as opposed to being set once & left alone...

All the formatting information needed by DateTime.Parse is contained in the
passed CutltureInfo object, As Herfried showed, DateTime.Parse will notice
that its a CultureInfo & actually use CultureInfo.DateTimeFormat property.
Likewise with CDec & CInt, if they need to follow the specific culture,
there is Decimal.Parse & Integer.Parse that accepts a CultureInfo object.
o.price = Decimal.Parse(d.price, culture)
o.quantity =Integer.Parse(d.quantity, culture)

Both Decimal.Parse & Integer.Parse will see the CultureInfo and actually use
CultureInfo.NumberFormat.

CDate, CDec, & CInt use the same CultureInfo object, they just don't allow
you to pass it directly, instead they rely on a global variable... Maybe MS
could simplify it for you & beginner VB.NET developers by allowing you to
specify the format or culture on VB.NET's conversion functions. Rather then
try to explain why you might use DateTime.Parse or DateTime.ParseExact
instead of the CDate. Would you understand it better if you could do the
following?
Dim ci As New Globalization.CultureInfo(d.culture)
o.orderdate = CDate(d.orderdate, ci)
o.deliverydate = CDate(d.deliverydate, ci)
o.price = CDec(d.price, ci)
o.quantity = CInt(d.quantity, ci)

In other words: CDate, CDec, & CInt do not allow you to specify the
CultureInfo needed, I am suggesting using DateTime.Parse rather then change
a global variable/setting.

Note: In your example, you are not restoring the original value of the
"global variable" CurrentCulture. At the very least save the current
CurrentCulture, then return the CurrentCulture to the one you save.

Dim startingCulture As CultureInfo =
Threading.Thread.CurrentThread.CurrentCulture
Try
Threading.Thread.CurrentThread.CurrentCulture = _
New Globalization.CultureInfo(d.culture)
o.orderdate = CDate(d.orderdate)
o.deliverydate = CDate(d.deliverydate)
o.price = CDec(d.price)
o.quantity = CInt(d.quantity)
o.culture = d.culture
Return myError
Catch ex As Exception 'However whatever error set
'evaluate(myerror, ex)
Return myError
Finally
Threading.Thread.CurrentThread.CurrentCulture = _ startingCulture
End Try


Consider what happens if at the top of the Main routine the CurrentCulture
is set to a specific culture:
Shared Sub main()
' we have many different installed cultures on our network
' we need to insure that German - Switzerland is used all the time!
Threading.Thread.CurrentThread.CurrentCulture = _
New Globalization.CultureInfo("de-CH")
Dim d As New document

More then likely the above would be an ASP.NET app, and the CurrentCulture
is determined by the login routine, seeing as the ASP.NET app is world wide,
the CurrentCulture will be very different then the InstalledUICulture!


The Apples:

The other examples include a specific date format, they have nothing to do
with changing the culture!

For example, if I am exchanging text or XML documents between the US, The
Netherlands, Switzerland, Germany & Japan, having the date in a specific
format, such as Year, Month, Day is required otherwise we would get Oct 1
confused with Jan 10. In this case I would use DateTime.ParseExact to
convert the date string in a specific format in the text document to an
actual DateTime object.

' dates are always in Year, Month, Day format!
o.orderdate = DateTime.ParseExact(d.orderdate, "yyyy/MM/dd",
nothing)
o.deliverydate = DateTime.ParseExact(d.deliverydate,
"yyyy/MM/dd", nothing)

In the two aforementioned threads I am discussing this last scenario.

I'm really hoping that this is helping!
Jay
 
Jay B. Harlow said:
Cor,
Ah! There's the rub, you are talking Oranges; Herfried, Jon & I are
talking Apples! :-)

The Oranges:

Actually in Your Example I would use DateTime.Parse:

Instead of:

I would use:
Dim culture As New Globalization.CultureInfo(d.culture)

o.orderdate = DateTime.Parse(d.orderdate, culture)
o.deliverydate = DateTime.Parse(d.deliverydate, culture)

Why?

I am asking that in every message however did not get an answer not from you
and not from Herfried. Microsoft advises to use the Microsoft.VisualBasic
conversion functions for this. Do you know something that there is wrong in
documentation from Microsoft about this.? Or is there a piece of
documentation I never saw. Until that I relly on this from this page.

=========================================================
http://msdn.microsoft.com/library/d...tml/vbtchmicrosoftvisualbasicnetinternals.asp
Conversion Functions, CType, DirectCast, and System.Convert
Visual Basic .NET includes data type conversion keywords, many of which are
carried over from Visual Basic 6. But unlike the Visual Basic 6 functions,
these keywords are not function calls but intrinsic language features. The
keywords CBool, CByte, CChar, CShort, CInt, CLng, CSng, CDbl, CDec, CDate,
CObj, and CStr map to Visual Basic Runtime method calls, .NET Framework
class library method calls, or IL type conversion instructions. The exact
method call or IL instructions generated depends on the expression against
which the conversion is being applied. Some conversions are optimized away,
such as CInt(123.45) which is replaced with the integer constant 123 in the
IL. This is an example where using the Visual Basic Runtime results in
better performance than using the System namespace. CInt("123") becomes a
call that leads to calls to System.Double.Parse then System.Math.Round.
CStr(4853) is ultimately handled by System.Int32.ToString. Conversions that
are not optimized away eventually lead to methods in the System namespace,
but there is no significant performance benefit when using the System
namespace methods directly. Furthermore, the Visual Basic compiler is able
to perform certain optimizations on conversions using the language keywords
that it does not perform on conversions done through the System namespace.

---------------------------------------------------------------------------------------
Notice that I am simply passing the culture required in the above, rather
then relying on the "global variable" CurrentCulture. By passing the
cutlure as a parameter, I don't need a Try/Finally to restore the "global
variable"

The Try/Finally is not for the global variable setting however to catch
mistypings and throwed errors by the validation from the orderclass wich can
than be catched and processed by the sender of the DocumentToOrder
procedure.
CurrentCulture. Also I do not risk changing the "global variable"
CurrentCulture that routines that ConvertDocumentToOrder may call require
set in a specific way. Yes you want it changed for CDate, however you may
not want it changed for CDec or CInt! For example changing the decimal
separator from a comma to a period. Plus you may call one of your own

Obvious I want to change those, do you not know that they are part of
culture settings and in an ASPNET application would be than very important.
routines (or team's routines) that requires the CurrentCulture to be a
specific value.

What I would do in my orderclass, with the culture however I thougth that
everybody would understand that.
I hope you agree tracking down problems with "global variables" in a
program can be very difficult, especially when they are being set & reset
all over the program, as opposed to being set once & left alone...

You are using them in every line. That is exact why I tell to use a global
setting and when that is build in, use that. .
All the formatting information needed by DateTime.Parse is contained in
the passed CutltureInfo object, As Herfried showed, DateTime.Parse will
notice that its a CultureInfo & actually use CultureInfo.DateTimeFormat
property. Likewise with CDec & CInt, if they need to follow the specific
culture, there is Decimal.Parse & Integer.Parse that accepts a CultureInfo
object.
Again you avoid the avised methodes by Microsoft, can you give the
documentation where this is stated by Microsoft as better, it seems to me
code witch has very much change on errors.
Both Decimal.Parse & Integer.Parse will see the CultureInfo and actually
use CultureInfo.NumberFormat.

CDate, CDec, & CInt use the same CultureInfo object, they just don't allow
you to pass it directly, instead they rely on a global variable... Maybe
MS

I am very lucky with that, it is one of the basics from OOP programming to
narrowing everything as much as possible.
could simplify it for you & beginner VB.NET developers by allowing you to

Again I am not a beginner and it is not needed to simplify it for me, I can
everything understand what you and Herfried and Jon are writting. However I
use documentation you know not just empty writting, so show that.

And again do not make the suggestion that I am a beginner. I have pasted 20
replies I think with an answer in the same trend, however I stuffed them
all, I do not go to that low level of arguing.
specify the format or culture on VB.NET's conversion functions. Rather
then try to explain why you might use DateTime.Parse or
DateTime.ParseExact instead of the CDate. Would you understand it better
if you could do the following?

I showed you the Microsoft documentation, show yours. I think Microsoft did
a good job with that documtation, I do not understand your critique on that.
In other words: CDate, CDec, & CInt do not allow you to specify the
CultureInfo needed, I am suggesting using DateTime.Parse rather then
change a global variable/setting.

Again see my sentence by narrowing the change on errors.

By the way it was all the time DateTime.ParseExact where you and Herfried
where talking about as the best way to go, Google archives everything you
know. .
Note: In your example, you are not restoring the original value of the
"global variable" CurrentCulture. At the very least save the current
CurrentCulture, then return the CurrentCulture to the one you save.
Dim startingCulture As CultureInfo =
Threading.Thread.CurrentThread.CurrentCulture


Consider what happens if at the top of the Main routine the CurrentCulture
is set to a specific culture:

' we have many different installed cultures on our network
' we need to insure that German - Switzerland is used all the time!
Threading.Thread.CurrentThread.CurrentCulture =

Did you see that Thread.CurrentThread.CurrentCulture, dotNet is working with
threads which in themself are processing the steps, step by step so it will
be set in the end of my procedure evertime to the basic culture. Or by
setting it using the standard culture saved before when there is a bug as
Herfried wrote, that is really beginners work.
New Globalization.CultureInfo("de-CH")
They are in the Net, you do not have to set them.
More then likely the above would be an ASP.NET app, and the CurrentCulture
is determined by the login routine, seeing as the ASP.NET app is world
wide, the CurrentCulture will be very different then the
InstalledUICulture!

My sample is exatly made for ASPNET, it seems you did not read it, it should
work for documents from all over the world not only for Japan, Germanny, the
Netherlands, etc. where a culture setting is.

And in my sample you have nothing to do for it. (With the exception that the
IIS server variables are at the moment not sufficient for it, so we have to
wait on better ones, by instance the clientsertificates) and therefore needs
there to be field from the client at the moment where he tells his language
and country (by instance for Canada) what than can be done in my opinon by
an checked to a keys of an Idictionary implementing class which gives than
as value the culture.

I would say, try the sample and add some cultures, maybe than you understand
it better.

Cor
 
Cor
I'm sorry, I am not discussing this matter with you any further.

I am more then willing to help people who are actually willing to be helped.
You however...

Its really not worth my time!

Good bye!

Jay
 
Cor Ligthert said:

You snipped the explanation that goes directly after the quoted code in
Jay's post.
Microsoft advises to use the Microsoft.VisualBasic conversion functions
for this.
No.

Do you know something that there is wrong in documentation from Microsoft
about this.? Or is there a piece of documentation I never saw. Until that
I relly on this from this page.

The quoted part of the documentation does not talk about cultures.
The Try/Finally is not for the global variable setting however to catch
mistypings and throwed errors by the validation from the orderclass wich
can than be catched and processed by the sender of the DocumentToOrder
procedure.

Setting the current culture is like setting a global variable. This
variable needs to be set back.
You are using them in every line. That is exact why I tell to use a global
setting and when that is build in, use that. .

There is a difference. You snipped Jay's explanation.
Again you avoid the avised methodes by Microsoft

Microsoft doesn't give the advice to use 'C*' functions even if their use is
semantically incorrect...
Again I am not a beginner and it is not needed to simplify it for me, I
can everything understand what you and Herfried and Jon are writting.
However I use documentation you know not just empty writting, so show
that.

If you read the docs and took at look at how 'C*' methods are working in
matters of culture variance/invariance, then you would realize that the
'CDate' method calls 'Date.Parse' and passes the current culture to it. In
fact, we do /not/ want to work with the current culture but instead want to
use a certain culture. In order to be able to specify this specific culture
without changing the current culture we pass this culture in the culture
parameter of the 'Parse' method.
My sample is exatly made for ASPNET, it seems you did not read it, it
should work for documents from all over the world not only for Japan,
Germanny, the Netherlands, etc. where a culture setting is.

That's not the point. The point is that methods called by your
implementation will use the selected culture too, which is not always
desired.
 
If you just want to convert a string to a date using a certain culture, then
DateTime::Parse with the culture is the best bet. I'm not going to set the
thread culture just to do one call to CDate, which as Herfried said just
calls DateTime::Parse with the culture anyway. I vote with Herfried, Jay,
John.

YS
 
Did you read that page from Microsoft where I gave the link too?

It is obvious you did not, and with that are all answers on this message
given.

Cor
 
Jay,
I am more then willing to help people who are actually willing to be
helped.

I have the last year nowwhere asked for your help, your knowledge is far to
few for that, there was a time I missed VBNet knowledge, however I have not
the idea I mis not much from that as well anymore at the moment.

This were answers on flames from you where you consequently are telling that
I am a beginner. I am sure that I am longer in this business as you, however
not only as programmer but in almost every dicipline of it.

I have seen replys from others on your answers as well in this trend, it
would be good when you would read them and think once about them.

Cor
 
Cor Ligthert said:
Did you read that page from Microsoft where I gave the link too?

It is obvious you did not, and with that are all answers on this
message given.

I'm now leaving this discussion...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top