Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to convert Datetime 1

Status
Not open for further replies.

alisaif

ISP
Apr 6, 2013
418
AE
Hi,

cTime = "03:45:10pm"
?HOUR(CTOT(DTOC(DATE())+" "+cTime))
?MINUTE(CTOT(DTOC(DATE())+" "+cTime))

How can I convert 15:45 in 03:45pm?? Just reverse of the above. And, how can I extract 03, 45, 10 and PM separately?

Please reply

Thanks

Saif
 
First off, based on your code above, cTime is Not a DateTime value.
It is a String. And even that String does not contain a Date part.

If you want it to be a DateTime value you need to do something like:
Code:
dtTime = CTOT("2000-10-24T13:30:00")

If you still just want to work with the Time String, you can write your own function to extract the various parts of the time (Hr, Min, Sec) from the string and then, if "PM" and Hr <> 12 merely add 12 to the Hr.

Good Luck,
JRB-Bldr

 
The SET HOURS 12/24 setting will also make VFP either use 24 hour times or 12 hour + am/pm.

Besides that, just use

Code:
SET SYSFORMATS ON

And VFP will copy some of the formats you set in Windows, inlcuding whether to use AM/PM or not.

To enforce it:
Code:
cTime = "17:35:05"
SET HOURS TO 12
cTime12 = TTOC(CTOT(DTOC(DATE())+" "+cTime),2)
? cTime+"->"+cTime12
? 'H:'+GetWordNum(cTime12,1,":")
? 'M:'+GetWordNum(cTime12,2,":")
? 'S:'+GetWordNum(cTime12,3,": ")
? 'AM/PM:'+GetWordNum(cTime12,2," ")
? '----'
cTime = "03:45:10pm"
SET HOURS TO 24
cTime24 = TTOC(CTOT(DTOC(DATE())+" "+cTime),2)
? cTime+"->"+cTime24
? 'H:'+GetWordNum(cTime24,1,":")
? 'M:'+GetWordNum(cTime24,2,":")
? 'S:'+GetWordNum(cTime24,3,":")

You don't have to do any conversions, if you store datetimes using the datetime type. Then it's merely SET HOURS TO 12 to display AM/PM timesand SET HOURS TO 24 to display 24 hour times.
And there's absolutley nothing to do, if you SET SYSFORMATS ON and let the display just be as the user sets it in Windows.

Bye, Olaf.


 
By the way, if you SET HOURS TO 25, you'll have one extra hour every day to implement datetime usage into your software, until you set it back to 24.

Bye, Olaf.
 
Thanks for the valuables suggestions, I will try it tomorrow.

Saif
 
Thanks I got it using Mr.Olaf's suggestion.

Saif
 
Olaf said:
By the way, if you SET HOURS TO 25, you'll have one extra hour every day to implement datetime usage into your software, until you set it back to 24.

You know, if this was widely known VFP might still be alive. [bigsmile]
 
Alsaif, just to demonstrate why you would not need to do anything, if you worked with datetimes instead of time strings:

Code:
Local ltDateTime

ltDatetime = DateTime() && set a variable to "now"
SET HOURS TO 24
? "In 24h format:",ltDatetime
SET HOURS TO 12
? "In am/pm format:", ltDatetime
SET SYSFORMATS ON
? "However Users have set up Windows:", ltDatetime

And in regard of SYSFORMATS, this is not only about 12 or 24 hours, this also is about short/long date format and day/month order, separators and more. You have to do nothing in regard of transforming values, the one and same value ltDatetime is not in any format, it's a binary containing the info about all the single datetime values year, month, day, hour, minute, and second, totally independent of any formatting, and turns into whatever human readable string your want.

Sure, it'll not be an easy transition from storing and processing time strings to processing datetimes, but you even won't waste time and get lots of bonus caüpabilites, like easy computation of differences:
Code:
Local ldDate1, ldDate2, ltDateTime1, ltDateTime2
ldDate1 = DATE()
ldDate2 = ldDate1 + 2*7 && date in two weeks
ltDateTime1 = DATETIME()
ltDateTime2 = ltDateTime1 + 5*60 && Datetime in one minute
? ldDate1, ldDate2, "difference:", ldDate2-ldDate1, ", that's", (ldDate2-ldDate1)/7, "weeks"
? ltDateTime1, ltDateTime1, "difference:", ltDateTime2-ltDateTime1, ", that's", (ltDateTime2-ltDateTime1)/60, "minutes"
? "time difference in HH:MM:SS format (not counting days):", TTOC(DTOT(Date())+(ltDateTime2-ltDateTime1),2)

In software, any software, you store the native computer binry tyypes like date, datetime, and you only display human readable. If you browse a table with binaray datetime, it'll display human reaadyle, too. No need to do anything but sepcify the wanted formatting right before displaying, the value of the datetime changes in no way by that. If you work a lot with strings, you're always concerned with transformations, which are not at all necessary, if working with appropriate types.

And last not least the example code I gave you took to convert from 12 to 24 and vice versa is converting an am/pm string while in 24 hours setting, so VFP is clever enough to interpret a datetime string evn not in the current output format:
Code:
SET MARK TO "."
? DATE(), "in format 99.99.9999"
? CTOD("03/03/2017"), "converted from format 99/99/9999, even though current format is 99.99.9999"
SET MARK TO "/"
? DATE(), "in format 99/99/9999"
? CTOD("03.03.2017"), "converted from format 99.99.9999, even though current format is 99/99/9999"

I already showed you SET SYSFORMATS, SET HOURS and SET MARK, also good to know are SET CENTURY ON/OFF, SET DATE TO DMY/MDY, SET DATE ANSI/AMERICAn/BRITISH/..., well you have intellisense showing all options. but in the end to show data, like dates, datetimes, currency, numbers, etc. as a windows user is used to, all you need to do is SET SYSFORMATS ON, and that'll effect all the simpler settings like MARK, POINT (decimal point vs. comma), date separator, century on/off, etc.

The juggling with strings is totally unnecessary, if you start with datetimes.

There are some difficulties in detail, eg you can't easily set a textbox controlsource to a datetime and let a user only see the time portion, only modifying or entering it, for that reason a conversion of entered time strings to todays datetime is a good to know expression, but as demonstrated, you don't even need to know whether the user enters 5:00pm or 17:00, both convert to 17:00, independent on what VFP displays due to SET HOURS.

Bye, Olaf.
 
Hi Alisaif,

I think you already make it. But just in case, this code can help. The used of this is to convert system time [time() -@military time] to 12hrs format.

*****try copy the code and name the program to mytime.prg
***code starts here

Function mytime
parameter TIME
private h24to12, hour, hr_total, oldtime, x
WithSecs = .F.
OLDTIME = TIME
DO CASE
CASE PARA() > 1
WAIT WINDOW 'Invalid No. of Parameters!' NOWA
RETURN ""
CASE PARA() = 1
IF TYPE('TIME') = 'N'
OLDTIME = TIME()
withsecs = .T.
ELSE
IF TYPE('TIME') # 'C'
WAIT WINDOW 'Invalid Data Type!' NOWA
RETURN ""
ELSE
IF ISAL(TIME)
WAIT WINDOW 'Invalid Data Type!' NOWA
RETURN ""
ELSE
IF LEN(OLDTIME) > 5 OR LEN(OLDTIME) < 3
WAIT WINDOW 'Invalid Time!' NOWAIT
RETURN ""
ENDIF
OLDTIME = TIME
ENDIF
ENDIF
ENDIF
CASE PARA() = 0
OLDTIME = TIME()
ENDCASE
FOR I=1 TO LEN(OLDTIME)
CHAR = SUBSTR(OLDTIME, I, 1)
DO CASE
CASE I = 1 OR I = 4 OR I = 5
IF !ISDIGIT(CHAR)
WAIT WINDO 'Invalid Time!' NOWA
RETURN ""
ENDIF
CASE I = 2 OR I = 3
IF !ISDIGIT(CHAR)
IF CHAR # ":" OR I = LEN(OLDTIME)
WAIT WINDO 'Invalid Time!' NOWA
RETURN ""
ENDIF
ENDIF
ENDCASE
ENDFOR
hour = val(left(oldtime, at(":",oldtime)-1))
minutes = VAL(SUBS(oldtime, AT(':',Oldtime)+1, LEN(OLDTIME)))
IF hour > 24
WAIT WINDOW 'Invalid Hour!' NOWAIT
RETURN ""
ELSE
IF minutes > 59
WAIT WINDOW 'Invalid Minutes!' NOWAIT
RETURN ""
ENDIF
ENDIF
If hour = 0
h24to12 = Stuff(oldtime,1,2,"12:")+" AM"
ELSE
hr_total = hour - 12
Do Case
Case hr_total < 0
IF WITHSECS
h24to12 = oldtime+" AM"
else
X = ALLT(STR(HOUR))+":"+IIF(minutes = 0, '00',;
RIGHT('00'+ALLT(STR(minutes)),2))+" AM"
h24to12 = Right(x, Len(x))
ENDIF
Case hr_total > 0
x = ltrim(Str(hr_total))
h24to12 = Stuff(oldtime,1,2,x)+" PM"
Otherwise
h24to12 = Stuff(oldtime,1,2,"12")+" PM"
EndCase
ENDIF
If left(h24to12,1) = "0"
h24to12 = subst(h24to12,2,len(h24to12))
Endif
IF LEN(h24to12) = 10 OR LEN(ALLT(STR(VAL(left(h24to12, at(":",h24to12)-1))))) = 1
h24to12 = " "+h24to12
ENDIF
IF !WITHSECS
h24to12 = LEFT(h24to12,5)+" "+RIGHT(h24to12,2)
ENDIF
Return h24to12
***********************end of program and save to mytime.prg OR PLEASE COPY MY PROGRAM.

**to test
in the command windows, SET PATH TO or DEFAULT TO the directory where mytime.prg was saved. From here, you can get the following
1. hr =left(mytime(),2)
2. mn =SUBSTR(mytime(),4,2)
3. sc =RIGHT(TIME(),2)
4. ?HR,MN,SC <enter> and see the result

Hope can help.


Best,





JunMagoncia
Manila,
Philippines
 
 http://files.engineering.com/getfile.aspx?folder=56396435-f408-42ff-becb-d742d71d3e4a&file=mytime.PRG
Hello Mandaragit,

Hello and welcome. Thank you for your contribution.

Take away a few tips to enhance your code:

Code:
CASE PARA() > 1
WAIT WINDOW 'Invalid No. of Parameters!' NOWA

If you pass in more parameters into a function, than it offers as parameters, this will lead to error 94 and your code checking the parameterization correctness won't run - this can be skipped. Parameter count checking is only useful in case of optional parameters, it would also be no good practice to add more parameters to the PARAMETERS/LPARAMETERS line to then check whether PARA exceeds the maximum number of parameter. And besides you rather should use PCOUNT() for reasons explained in the PCOUNT() help topic.

Code:
IF TYPE('TIME') = 'N'
OLDTIME = TIME()
withsecs = .T.

This buries a convention of the function use I don't really see the merit of, if the passed in parameter is not a string, you set OLDTIME to the current TIME() string. That part may be a automatic fix nice to have, but then withsecs=.T. indicates the mode of the function changes automatically. Anyway, no need to dig into this issue, as the next line contradicts the handling of different passed in parameter types:
Code:
IF TYPE('TIME') # 'C'
WAIT WINDOW 'Invalid Data Type!' NOWA
RETURN ""

This introduces the more important problem of your function. A good simple such conversion function has no visual display, it will return or throw errors. Display of messages is rather bound to the valid event of a control for entering times as the WAIT WINDOW emulates what you can do with control.errormessage for legacy compatibility, but are advised to do in a Valid event in VFP. If your code would simply do ERROR 'message' in all places you now do WAIT WINDOW, the Valid event of a time entry textbox could use it via

Code:
TRY
   convertedtime = mytime(this.value)
CATCH TO loException
   WAIT WINDOW loException.Message
ENDTRY

That's very simplified usage, you may want to catch a few errors differently and of course make some use of the converted time.

So the problem is not really the WAIT WINDOW, that's a matter of taste, but it should be done on the interface level and not on the level of function code. You entangle your code with input validation and you only indicate an error to the end user visually, this function could not be part of unit testing, all the unit testing code would get back in any error case is an empty string.

A nice way also is to turn the function into a function mainly returning an error number (or 0 for no error) and return its main function result by a byref parameter - passing in parameters by refrecence via prefixing them with @, returning the result by changing the parameters themselves. That type of functions have the disadvantage of only be really applicable to functions returning the same simple type passed in, as you otherwise change variable type, though VFP itself has no problem with that, it disables usage as COM object. This type of function can then rather work on objects and besides has the advantage to be able to have mutiple results, eg act on multiple simple type parameter variables or multiple properties of a passed in object and even make use of some method of the passed in object. It's a double edged sword, a simple function like that should not implement, but always a topic to think about, if you have very specific error handling and error detection of more than just the initial type check. A timehandler class could have multiple time related methods and to indicate errors use an nLastError property for example, in case of checking time string input, it could also have a property indicating the part of the time string identified as wrong to let the user interface highlight that.

Finally, In this case, that functionality should rather be a method of a textbox class specifically designed for display and entering of times. Making such a validation function a method, acting on the control.value or backcolor or selstart and sellength to point out the input error would be valid functionality and visual feedback as the functionality then is integrated into the interface control.

So very generally speaking, if you intend to involve something with the UI you thereby decide to work on UI classes and should do so, not have a separate PRG file and simple function. The underlying principle is encapsulation.

Bye, Olaf.
 
Hi Olaf

Thank you for a very nice suggestion. This sound good to me. I am just happy to know that there are still FoxPro lovers exist. From now on, i'll be visiting this forum often.

Again, thank Olaf.



JunMagoncia
Manila,
Philippines
 
JunMagoncia, I will add my welcome. I see you have been active in the SBT forum. I hope you will enjoy the VFP forum as well.

If I may make a suggestion: Spend a few minutes looking at the Help screen regarding the forum's editing and posting. You can get to it from the toolbar just above the editing window. There is a small Help icon at the right-hand end of the toolbar, next to the big Preview button.

In particular, see how to use the [ignore]
Code:
[/ignore] tags. These are very useful when you a posting program code, as it enables you to retain the indentation of the original code, which makes it easier to understand the logic. If you glance through the threads in this forum, you'll see many places where it has been used for good effect (and some places where it hasn't, for not so good effect).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi MikeLewis

Thank you so much. Seems what you said now, is what i am looking for. As I don't spent time looking for a provision to retain the indention of my sample code, therefore the result is that, the presentation become non standard and hard to understand to someone who read it unless, will copy and paste it to FoxPro and align everything.

Anyway and again my friend, Mike, thank you and I expect you also in SBT forum, hehehe. Have a blessed day!


Best,



JunMagoncia
Manila,
Philippines
 
Thank Mr.JunMagoncia Nice piece of code with a pretty brush up by Mr.Olaf.

I will the same in my function.

Thanks

Saif
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top