Domyślny FormatSettings dla aplikacji

0

Witam,
Domyślnym ustawieniem formatu daty w Windows jest dd.MM.yyyy. Każdy może w ustawieniach zmienić ten format dla wygody, kaprysu albo oczekiwań jakiejś aplikacji. I to jest ok.
Z poziomu Delphi możemy odczytać bieżące ustawienia systemu

GetLocaleFormatSettings(1045,FS);

gdzie FS: TFormatSettings, a 1045 to język polski.
Możemy też prosto zmienić format daty, czasu i separatorów itd. i pobawić się różnym ich wyświetlaniem

    showmessage(FS.ShortDateFormat);
    showmessage(FS.DateSeparator);
    showmessage(datetostr(now)+#13+datetostr(now,FS));
    fs.DateSeparator:='-';
    showmessage(datetostr(now)+#13+datetostr(now,FS));
    FS.ShortDateFormat:='yyyy-MM-dd';
    showmessage(datetostr(now)+#13+datetostr(now,FS));

To wszystko jest raczej znane i opisane w wielu postach, gdyż mając dwie opcje wywołania datetostr:

function datetostr ( Date : TDateTime ) : string;
function datetostr ( Date : TDateTime; const FormatSettings : TFormatSettings ) : string;

zawsze możemy dodać jako drugi parametr ustawienia formatowania.

Szukam rozwiązania, które pozwoli na ustawienie wartości FormatSettings w obrębie aplikacji, bez każdorazowego dodawania tego drugiego parametru.
Czy można dynamicznie podmieniać ustawienia systemowe, by wywołanie datetostr(now) zwróciło ustawiony dla aplikacji, a nie systemowy format?

5

Zmodyfikuj wartości globalnych zmiennych (w nowszych Delphi to rekord) np:

SysUtils.ShortDateFormat:= 'yyyy MMMM dd';

albo dla nowych Delphi:

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy MMMM dd';
0

Dzięki za błyskawiczną pomoc - działa :)
Poniższe zadziałało na Win 10 Pro i Rad Studio 10 Seattle.
Dodam co zaskoczyło mnie, że taka sekwencja:

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy MM dd';
System.SysUtils.FormatSettings.DateSeparator:='-';

zwracała daty w postaci '2016 02 21' mimo zdefiniowania separatora,
no to dodałem myślniki kasując drugą linię (bo po co dwa razy):

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';

i mam "2016-02-21 is not a valid date".
Dopiero ustawienie obu linii

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';
System.SysUtils.FormatSettings.DateSeparator:='-';

dało poprawny efekt.
Czyli mimo ustawienia w Windows krótkiej daty na dd.MM.yyyy w obrębie aplikacji datetostr zwraca yyyy-MM-dd.
O co chodziło.
Dzięki za pomoc i pozdrawiam.

4

@delphi_fan — o ile istnieje zgodność pomiędzy Delphi w wersji którą posiadasz a FPC, Twój kod wcale nie podstawia zdefiniowanego separatora. Czyli taki kod:

// Twoja część
System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';
System.SysUtils.FormatSettings.DateSeparator:='-';

// przykładowe wyświetlenie daty
WriteLn(FormatDateTime(SysUtils.FormatSettings.ShortDateFormat, Now()));

co prawda wyświetli wartość 2016-02-21, jednak bez zdefiniowania DateSeparator, program także wyświetli datę ze znakami -. Powtarzam jeszcze raz — o ile istnieje zgodność (niestety sam nie mam jak tego sprawdzić), znak - nie jest domyślnym znakiem separatora daty, więc funkcja konwertująca (w tym przypadku użyta FormatDateTime) w ogóle nie rozpozna znaku - i go po prostu przepisze.

Dla przykładu, poniższy kod:

SysUtils.FormatSettings.ShortDateFormat := 'YYYY-MM-DD';
SysUtils.FormatSettings.DateSeparator := '|';

WriteLn(FormatDateTime(SysUtils.FormatSettings.ShortDateFormat, Now()));

nie podstawi w miejsce - zdefiniowanego separatora daty. Natomiast jeśli użyjemy w masce ShortDateFormat jednego ze znaków domyślnych — czyli / — funkcja konwertująca wstawi w jego miejsce znak zdefiniowany:

SysUtils.FormatSettings.ShortDateFormat := 'YYYY/MM/DD';
SysUtils.FormatSettings.DateSeparator := '|';

WriteLn(FormatDateTime(SysUtils.FormatSettings.ShortDateFormat, Now()));

Taki kod spowoduje wyświetlenie w konsoli daty w postaci 2016|02|21, czyli z użyciem znaku z pola DateSeparator.

Analizując dogłębniej, każdy łańcuch znaków określający długi lub krótki format daty i/lub czasu może zawierać dodatkowe nieformatowane podciągi, nawet jakieś kosmiczne wartości. Poniższy kod:

SysUtils.FormatSettings.ShortDateFormat := '"rok "YYYY", miesiac "MM" i dzien "DD';
WriteLn(FormatDateTime(SysUtils.FormatSettings.ShortDateFormat, Now()));

wygląda dziwnie, jednak jest to dozwolone. Co zostanie wyświetlone w konsoli? To:

rok 2016, miesiac 02 i dzien 21

Dlaczego? Bo znakami " obejmuje się podciągi, które są przepisywane do łańcucha wyjściowego. To jedna z wielu ficzerów dotyczących formatowania łańcuchów. Jeżeli nie używa się znaków cudzysłowu to wszystkie znaki nieokreślające formatowania którejść składowej zostaną przepisane (o ile znaki te są neutralne).

Kolejny przykład:

SysUtils.FormatSettings.ShortDateFormat := '-.,YYYY-.,MM.,-DD-;%';
WriteLn(FormatDateTime(SysUtils.FormatSettings.ShortDateFormat, Now()));

Maska zawiera znaki nautralne — znaki -, . i , — więc na wyjściu dostaniemy wartość -.,2016-.,02.,-21-;%.


Dlaczego o tym wspominam — jeśli potrzebujesz użyć własnoręcznie zdefiniowanego separatora składowych daty w skróconej wersji formatu daty, znaku który jest inny niż domyślny, to albo użyj go od razu w łańcuchu maski:

SysUtils.FormatSettings.ShortDateFormat := 'YYYY-MM-DD';  // tyle wystarczy

albo użyj w masce znaku domyślnego (znaku /) i ustaw swój własny znak w odpowiednim polu:

SysUtils.FormatSettings.ShortDateFormat := 'YYYY/MM/DD';  // tu wykorzystanie domyślnego separatora
SysUtils.FormatSettings.DateSeparator := #10;  // tu zdefiniowanie własnego, który zostanie podstawiony

O ile Delphi w ten sam sposób wykorzystuje FormatSettings co FPC — ten post powinien być dla Ciebie pomocny. A jeśli istnieją różnice — coż, pozostanie jako ciekawostka dla programujących pod FPC.

0

Cześć Koledzy,

w windows 11 mam taki problem. Ustawiam swój format daty dla całej aplikacja w Unit1 w zdarzeniu onCreate:

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';
System.SysUtils.FormatSettings.DateSeparator:='-';

Wszystko działa poprawnie, ale przez pewien czas. Nie wiem dlaczego Windows 11 zmienia Mi Mój format daty w aplikacji po jakimś czasie..

Już odpowiadam na temat kodu, zapisuje date do stringa do listview w postaci FormatDateTime('yyyy-MM-dd',now);
Odczytuje StrTodate(wew_data); tyle się dziej z datami w kodzie.

Po pewnym czasie jak chce odtworzyć zapisany rekord mam komunikat ivalid format date 2022-04-01. Mimo iz tak ustawiłem formatowanie na początku tworzenia aplikacji..

Jak uruchomię aplikacje ponownie, otwieram ten sam rekord i jest już ok.

Mam tak od czasu aktualizacji windows 11, już nawet myślę włożyć w timera sprawdzanie co sekundę, lub dodac kod zmiany daty przed kazda operacja na datach, ale to paranoja..

Macie może jakieś pomysły jak to naprawić lub ustawić na stałe?

Dziękuje za pomoc.

1
var
  fs: TFormatSettings;
  dt: TDateTime;
begin
  fs.ShortDateFormat:= 'yyyy-mm-dd';
  //zapisz
  ListBox1.Items.Add(DateToStr(Now, fs));
  //odczytaj
  dt := StrToDate(ListBox1.Items[ListBox1.Items.Count - 1], fs);
end;
0

Dziękuje, myślałem o tym wcześniej ale to nie rozwiązuje problemu, bo muszę pamiętać o TFS w każdym miejscu z datą. Na chwile obecna robię tak ze przed wywołaniem odczytu dodaje:

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';
System.SysUtils.FormatSettings.DateSeparator:='-';
1

Następnym razem załóż swój wątek, bo odgrzewając kotleta powodujesz wysyłanie powiadomień do użytkowników, którzy już dawno temu zapomnieli o tym wątku, a nawet o tym forum.

Odpowiadając na pytanie — wszystkie funkcje konwersji daty i czasu bazują na domyślnym rekordzie z ustawieniami, czyli na DefaultFormatSettings (jest też w razie czego alias o nazwie FormatSettings). Aby zmienić globalne dane lokalizacyjne (globalne dla aplikacji, nie systemu) i wykluczyć konieczność przekazywania swojej struktury z ustawieniami, wystarczy zmodyfikować FormatSettings. To się robi raz, gdzieś na początku kodu, tak aby wszystkie wywoływane później własne metody miały przygotowane ustawienia.

0

Dziękuję, tak też robię ale jak wspomniałem Windows 11 podczas pracy w programie potrafi zmienić te wartości co Mnie dziwi, na win 10 tego problemu nie ma. Obecnie zastosowałem przed każdym wywołaniem procedury odnoszącej się do dat procedure z:

System.SysUtils.FormatSettings.ShortDateFormat:= 'yyyy-MM-dd';
System.SysUtils.FormatSettings.DateSeparator:='-';

To jakiś problem z windows 11, tak jak z przenoszeniem okien miedzy dwoma monitorami w dowolnej aplikacji nawet tych poza Delphi.

Problem zaczął występować na wszystkich komputerach w firmie z win 11 po aktulizacji ok 2 mc temu, te z win 10 nie mają takich problemów.

3

Spróbuj
Application.UpdateFormatSettings:= False;
Oczywiście tuż po ustawieniu Ci odpowiadającego formatu.

0

Innym rozwiązaniem jest korzystanie z własnej struktury TFormatSettings, wypełnionej takimi danymi jak chcemy. I tę strukturkę należy przekazywać we wszystkich wywołaniach funkcji konwertujących datę na ciąg znaków. Wszystko zależy od wymagań projektowych.

0

Akurat w Moim przypadku najlepszym rozwiązaniem jest zmiana globalna z wyłączona Update.

Jeszce raz dziękuję za pomoc Koledzy, dzięki!

1 użytkowników online, w tym zalogowanych: 0, gości: 1