String Modification

I have a timestamp string in the form “20220513” and want to modify it to the form “2022-05-13”. Is using the .Middle() method (3x) with concatenation the only way to go? It works; it just seems a little unwieldy.

You could do RegEx, but the Middle() approach is probably fine.
Or split, change array and join, but that may be slower.

Parsing the string manually is probably the best solution as I can’t think of a locale that uses that as a date format. If you want the extra validation that the framework can provide, you can do something like this:

var dateString as String = "20220513"
var d as new DateTime( dateString.Left(4).ToInteger, dateString.Middle(4, 2).ToInteger, dateString.Right(2).ToInteger )
var result as String = d.SQLDate

The framework will throw InvalidArgumentExceptions if the supplied values to the DateTime constructor are outside the expected range in addition to OutOfBoundsExceptions if your parsing exceeds the length of the string.

This will do it

dim theDate as string = "20220513"
msgbox Format(val(theDate), "0000\-00\-00")

(Feel free to translate to API2 if you want)

2 Likes

This won’t work with API2’s ToString, IIRC, due to the switch to using the unicode number format patterns.

You can see the difference with this code, which results in a value of 20,220,513.

theDate.ToDouble.ToString( "0000\-00\-00" )

Likewise, using ToInteger results in 20220513.

I looked at the Number Format Patterns spec and don’t see an arbitrary escape defined (I may be overlooking it, so please correct me if I’m wrong), so your solution would seem to only function with the API 1.0 Format function.

Oh well.
Thats progress I guess.

Maybe wrap it up with a replaceall ? (not a user of API2 myself)

theDate.ToDouble.ToString( "0000\-00\-00" ).Replaceall(",","-")

That would still give an incorrect value of 20-220-513. The good news is that, checking the documentation and analyzing in the IDE, Format doesn’t actually appear to be deprecated. I thought that it was. So your original solution would work just fine without a deprecation warning and it also doesn’t complain about val() so…yeah.

1 Like

Why do you use Double at all??? Converting a String representing a Date into a Double - why would you think that improves anything? On the contrary: THAT is where you get your problems.

1 Like

He used Val(), I was doing a 1:1 conversion of the code he provided to API2 based on his suggestion. It showed the difference quite well, I think.

See the rest of the discussion. Format versus ToString is the main problem point as using ToInteger also fails.

Why ?

Can’t you convert that to a computer Date - instead of a String - and display the Date for the human eye / keeping the computer Date object for the application internal use ?

If you have a short string and a defined format, what could be simpler as to cut it and concatenate the pieces to a result?

Two MVP‘s gave answers that overcomplicates the actual task. Are you serious?

1 Like

Even better is to convert all received dates to a Double containing the number of seconds since the epoch. That way date comparisons and increments by e.g. a week become trivial, and time zone ceases to be a problem. Then, for display to the user, convert to the format of their choice rather than yours.

1 Like

@Carsten_Belling

I provided one that does give some validation in the form of thrown exceptions in the case of invalid input. Sure, you could just slice the string and concatenate, which is what they said they’re already doing in the first post. No need for us to suggest what they’re already doing.

They are just answering with “other ways to go”.

I guess if the question was:

  • is it the best way to go?
  • is it the fastest way to go?
  • is it the safest way to go?

the answers could be different.

I have learned a lot from answers that do not simply answer my problem but give ideas that I was not aware. Maybe OP could need validation, maybe needs to convert to datetime object to better handle the situation, or maybe learning that format can help and .ToString uses a different format pattern than Format.

All of this is helpful when you want to learn because much of the time there is not a single way to do things. Maybe we can find other ways easier/clearer/safer/faster.

2 Likes

@AlbertoD and all others, you‘re right, there are always many ways to go. But when the OP has already gone the simplest way, why make it more complicate?
And BTW: The question was not to convert a string into a date and display it in a locale format or wharever. He asked for a simpler way and no one provides one. The answers (of the MVP‘s) are fine, but I miss the remark as like „If you want more than reformat that string then you can use RegEx, the DateTime class etc.“.

Sorry @Anthony_G_Cyphers, that is exactly what I meant and read over.

Thanks to this thread I learned that Format and .ToString don’t use the same pattern.

If someone just answered "you can use left(4) and right(2) too, and the thread was not answered anymore then I will still believe that the format pattern for String is the same as in Format. I don’t use .ToString much and less with a format pattern but is always good to know where things are different.

I know it is in the docs but I’m sure that I will not look at them until something is not working as I expect.

Personally I thank those that give extra answers (validation, be aware of the input/source, etc). It gives me an opportunity to learn.

I like the approach complicate once, simplify everything after, like:

Module StringDateTime

Public Function ToSQLDate(Extends dts As String) As String
  Var dt As DateTime
  Try
    If dts.Length=8 Then
      dt = DateTime.FromString(dts.Left(4)+"-"+dts.Middle(4,2)+"-"+dts.Right(2))
    Else
      dt = DateTime.FromString(dts) // Maybe something valid
    End
  Catch // Invalid date
    Return ""
  End
  
  Return dt.SQLDate
  
End Function

End Module

Use as

Var s As String  = "20220513"

MessageBox s.ToSQLDate

He asked for a simpler way and no one provides one.

Really?
does

Format(val(theDate), "0000\-00\-00")

look harder than

var d as new DateTime( dateString.Left(4).ToInteger, dateString.Middle(4, 2).ToInteger, dateString.Right(2).ToInteger )
var result as String = d.SQLDate

I do like Rick’s answer, however, as once it is written, usage later (assuming it needs to be used in multiple places in the app) becomes simpler, and has vaildation

3 Likes

The date as 8 characters is coming from an application that I didn’t write – I’m working with what I have. What I’m actually dealing with is a filename in the form:

log-20220514.txt

These files are collected in a folder and I want to be able to remove all but the last 14 days worth of logs (based on the date in the filename). This is the code that tells me how old the file is.

Var today As DateTime = DateTime.Now

// "log-20220513.txt" --> "2022-05-13"

fname = fname.Middle(4, 4) + "-" + fname.Middle(8, 2) + "-" + fname.Middle(10, 2)

Var target As DateTime = DateTime.FromString(fname)
Var dif As DateInterval = today - target

Return dif.days

I am new to Xojo, so I I ask questions.