Seite 1 von 2

[Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 29.06.2018 15:51
von NicTheQuick
Hi Leute,

das hier ist so ein Proof of Concept für die Darstellung eines Datums und der Zeit mittels locales. Es funktioniert bisher gut, aber es gibt auch einen Crash, der als Beispiel ganz unten auskommentiert ist und den ich nicht verstehe. Vielleicht hat da jemand eine Idee.

Ich möchte das ganze auch noch auf Zahlen und Geldbeträge ausweiten. Für Linux kein Problem, aber ich könnte Hilfe für die anderen Betriebssysteme gebrauchen. Und dann mache ich ein Module daraus. Wie gefällt euch die Parameterübergabe? Soll ich vielleicht das setlocale() sogar auslagern, sodass man es einmal setzt und dann kann man beliebig viele Date-Funktionen aufrufen?

Wichtig ist, dass es nur mit locales funktioniert, die auch installiert sind. Ihr findet das unter Linux heraus, indem ihr im Terminal "locale -a" eingibt. Neu hinzufügen für z.B. Russisch geht so:

Code: Alles auswählen

sudo locale-gen ru_RU.UTF-8
sudo update-locale
Und wenn ihr nicht wisst, was ihr noch installieren könntet, gibt es hier eine Liste: /usr/share/i18n/SUPPORTE

Hier aber nun der Code.

Code: Alles auswählen

Structure tm
	tm_sec.l	; seconds
	tm_min.l	; minutes
	tm_hour.l	; hours
	tm_mday.l	; day of the month
	tm_mon.l	; month
	tm_year.l	; number of years since 1900
	tm_wday.l	; day of the week
	tm_yday.l	; day in the year
	tm_isdst.l	; daylight saving time
EndStructure

Enumeration 1
	#LC_ALL
	#LC_COLLATE
	#LC_CTYPE
	#LC_MONETARY
	#LC_NUMERIC
	#LC_TIME
EndEnumeration

Import ""
	time(*rawtime)
	localtime.i(*rawtime)
	strftime(*dest, maxsize.l, format.p-utf8, *timeprt.tm)
	setlocale(t.i, locale.p-ascii)
EndImport

Procedure.s localDateTime(date.q, mask.s = "%x %X", locale.s = "")
	Protected bufferSize.i = 12
	Protected *result = AllocateMemory(bufferSize), *tResult
	Protected tm.tm, *oldLocale, oldLocale.s, result.s
	tm\tm_sec = Second(date)
	tm\tm_min = Minute(date)
	tm\tm_hour = Hour(date)
	tm\tm_mday = Day(date)
	tm\tm_mon = Month(date) - 1
	tm\tm_year = Year(date) - 1900
	tm\tm_wday = DayOfWeek(date)
	tm\tm_yday = DayOfYear(date) - 1
	tm\tm_isdst = 0
	
	*oldLocale = setlocale(#LC_TIME, locale)
	If Not *oldLocale
		DebuggerWarning("Locale could not be set: " + locale)
	Else
		oldLocale = PeekS(*oldLocale, -1, #PB_Ascii)
	EndIf
	
	
	While Not strftime(*result, bufferSize, mask, @tm)
		bufferSize * 2
		*tResult = ReAllocateMemory(*result, bufferSize, #PB_Memory_NoClear)
		If Not *result
			DebuggerWarning("Could not allocate enough memory for datetime conversion.")
			Break
		EndIf
		*result = *tResult
	Wend
	
	result = PeekS(*result, -1, #PB_UTF8)
	
	FreeMemory(*result)
	
	If *oldLocale
		setlocale(#LC_TIME, oldLocale)
	EndIf
	
	ProcedureReturn result
EndProcedure

Debug localDateTime(Date(2018, 3, 3, 0, 0, 0), "Heute ist %A. Wir haben %X Uhr und es ist der %x. Der Monat ist %B.", "de_DE.UTF8")

; Das hier crasht :(
;Debug localDateTime(Date(), "%c", "de_DE.UTF8")

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 29.06.2018 23:48
von Sicro

Code: Alles auswählen

*tResult = ReAllocateMemory(*result, bufferSize, #PB_Memory_NoClear)
If Not *result
ändern zu:

Code: Alles auswählen

*tResult = ReAllocateMemory(*result, bufferSize, #PB_Memory_NoClear)
If Not *tResult
Das Problem ist damit aber leider noch nicht gelöst.

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 07:28
von kapege
bei mir crasht nichts.
Win 7 64bit, Purebasic 5.61 64bit


Debug localDateTime(Date(2018, 3, 3, 0, 0, 0), "Heute ist %A. Wir haben %X Uhr und es ist der %x. Der Monat ist %B.", "de_DE.UTF8")

; Das hier crasht :(
Debug localDateTime(Date(), "%c", "de_DE.UTF8")

Heute ist Saturday. Wir haben 00:00:00 Uhr und es ist der 03/03/18. Der Monat ist March.
06/30/18 07:26:34

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 10:22
von NicTheQuick
Moment, das läuft auf Windows 7? :shock: Ist das etwa kompatibel? Es kommt trotzdem das falsche Ergebnis bei dir raus. Mit de_DE sollte natürlich alles deutsch sein.

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 10:56
von mk-soft
Im Header Datei von locale.h stehen bei mir andere Konstanten.
#LC_ALL = 0
#LC_COLLATE = 1
#LC_CTYPE = 2
#LC_MONETARY = 3
#LC_NUMERIC = 4
#LC_TIME = 5
#LC_MESSAGES = 6
Bei MacOS funktioniert es nicht mit der C++ Lib. Das setzen von locale auf andere Sprachen schlägt fehl.
Es wird nur "C" und "POSIX" akzeptiert.

P.S
Windows schlägt auch fehl...

UND

Linux schlägt fehl... Unter Linux steht locale schon auf Userdefault.

Test

Code: Alles auswählen

#LC_ALL       = 0
#LC_COLLATE   = 1
#LC_CTYPE     = 2
#LC_MONETARY  = 3
#LC_NUMERIC   = 4
#LC_TIME      = 5
#LC_MESSAGES  = 6

; Enumeration 1
;    #LC_ALL
;    #LC_COLLATE
;    #LC_CTYPE
;    #LC_MONETARY
;    #LC_NUMERIC
;    #LC_TIME
; EndEnumeration

Import ""
   setlocale(t.i, *locale)
EndImport

*oldlocale = setlocale(#LC_TIME, 0)
Debug "Default: " + PeekS(*oldlocale, -1, #PB_Ascii)

*locale = Ascii("")
Debug setlocale(#LC_TIME, *locale)
FreeMemory(*locale)

*locale = Ascii("de-DE.UTF8")
Debug setlocale(#LC_ALL, *locale)
FreeMemory(*locale)

*locale = Ascii("de-DE")
Debug setlocale(#LC_TIME, *locale)
FreeMemory(*locale)

*locale = Ascii("en-EN.UTF-8")
Debug setlocale(#LC_TIME, *locale)
FreeMemory(*locale)

*locale = Ascii("POSIX")
Debug setlocale(#LC_TIME, *locale)
FreeMemory(*locale)

*locale = Ascii("C")
Debug setlocale(#LC_TIME, *locale)
FreeMemory(*locale)

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 11:56
von mk-soft
Wie es aus sieht kann man nur zwischen Userdefault und "C" mit setlocale wechseln.
Nur bei MacOS geht es nicht.

Update 'C'

Code: Alles auswählen

Structure tm
  tm_sec.l   ; seconds
  tm_min.l   ; minutes
  tm_hour.l  ; hours
  tm_mday.l  ; day of the month
  tm_mon.l   ; month
  tm_year.l  ; number of years since 1900
  tm_wday.l  ; day of the week
  tm_yday.l  ; day in the year
  tm_isdst.l ; daylight saving time
EndStructure

#LC_ALL       = 0
#LC_COLLATE   = 1
#LC_CTYPE     = 2
#LC_MONETARY  = 3
#LC_NUMERIC   = 4
#LC_TIME      = 5
#LC_MESSAGES  = 6

ImportC ""
  time(*rawtime)
  localtime.i(*rawtime)
  strftime(*dest, maxsize.l, format.p-utf8, *timeprt.tm)
  setlocale(t.i, *locale)
EndImport

Procedure.s localDateTime(date.q, mask.s = "%x %X", locale.s="")
  Protected bufferSize.i = 12, *locale
  Protected *result = AllocateMemory(bufferSize), *tResult
  Protected tm.tm, *oldLocale, oldLocale.s, result.s
  tm\tm_sec = Second(date)
  tm\tm_min = Minute(date)
  tm\tm_hour = Hour(date)
  tm\tm_mday = Day(date)
  tm\tm_mon = Month(date) - 1
  tm\tm_year = Year(date) - 1900
  tm\tm_wday = DayOfWeek(date)
  tm\tm_yday = DayOfYear(date) - 1
  tm\tm_isdst = 0
  
  *locale = Ascii(locale)
  
  *oldLocale = setlocale(#LC_TIME, 0)
  If Not setlocale(#LC_TIME, *locale)
    DebuggerWarning("Locale could not be set: " + locale)
    Debug "No set"
  EndIf
  
  
  While Not strftime(*result, bufferSize, mask, @tm)
    bufferSize * 2
    *tResult = ReAllocateMemory(*result, bufferSize, #PB_Memory_NoClear)
    If Not *result
      DebuggerWarning("Could not allocate enough memory for datetime conversion.")
      Break
    EndIf
    *result = *tResult
  Wend
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    result = PeekS(*result, -1, #PB_Ascii)
  CompilerElse
    result = PeekS(*result, -1, #PB_UTF8)
  CompilerEndIf
  
  FreeMemory(*result)
  
  If *oldLocale
    setlocale(#LC_TIME, *oldLocale)
  EndIf
  
  FreeMemory(*locale)
  
  ProcedureReturn result
EndProcedure

Debug localDateTime(Date(2018, 3, 28, 12, 0, 0), "Heute ist %A. Wir haben %X Uhr und es ist der %x. Der Monat ist %B.")
Debug localDateTime(Date(2018, 3, 28, 12, 0, 0), "Heute ist %A. Wir haben %X Uhr und es ist der %x. Der Monat ist %B.", "C")

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 15:00
von #NULL
geht :D , Ubuntu 16.04

Code: Alles auswählen

Heute ist Samstag. Wir haben 00:00:00 Uhr und es ist der 03.03.2018. Der Monat ist März.
Sa 30 Jun 2018 15:00:20 d

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 15:30
von _JON_
ImportC "" ... sonst crashed es mit 32bit Compiler.

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 17:41
von Sicro
NicTheQuick hat geschrieben:Moment, das läuft auf Windows 7? :shock: Ist das etwa kompatibel?
Du importierst ja die Befehle von C++ ... :-)
#NULL hat geschrieben:geht :D , Ubuntu 16.04

Code: Alles auswählen

Heute ist Samstag. Wir haben 00:00:00 Uhr und es ist der 03.03.2018. Der Monat ist März.
Sa 30 Jun 2018 15:00:20 d
So sieht das bei mir auch aus, wenn ich die Debugs zu einem MessageRequester abändere und den Debugger abschalte.
Das "d" am Ende deutet aber darauf hin, dass die Ausgabe abgeschnitten und somit unvollständig ist.

Re: [Linux, Win?, Mac?] DateTime mit Locales

Verfasst: 30.06.2018 23:38
von NicTheQuick
Muss ich mir noch mal angucken. Komme wohl erst wieder am Montag dazu.