Format daty systemowej

0

Witam,

Napisałem system zarządzania pracownikami, którego baza danych opiera się na plikach INI. Program jest używany na komputerach z Systemem Windows, ale w różnych językach: niemiecki, polski, angielski.

Problem polega na tym, że mam już w programie (Windows Niemiecki) utworzoną bazę danych - daty, godziny itp. itd. - ale ta baza nie jest kompatybilna z wersją Windows Polski, z powodu różnicy w zapisie dat.

Polski: 2011-07-10
Niemiecki: 10.07.2011

Gdy próbuję odtowrzyć bazę danych utworzoną na systemie windows niemieckim, nie wczytuje mi danych z datą, lub wywala błąd **'invalid date value 10.07.2011' **etc.

Chciałbym zrobić domyślny system zapisywania dat do pliku i odczytywania go w bez względu na język systemu.
Czy samo

FormatDateTime('dd.mm.yyyy', Date);

wystarczy, aby konwertować daty i operować na nich bezproblemowo, czyli np:

; Plik ini POLSKI
[Sekcja 1]
Data=2011-09-10

Odczyt:

var
  Data: string;
begin
INI.ReadString('Sekcja 1', 'Data', ''); // Readstring dlatego, że gdy dam readdate, a data została zapisana w wersji niemieckiej wywali mi blad
FormatDateTime('dd.mm.yyyy', StrToDate(Data)); // Czy to zadziała ?
{
   Teraz jak operować na zmiennej Data, skoro nie wiadomo, na jakiej wersji systemowej została odpalona ?
   Czy muszę zaimplementować w kodzie sprawdzanie języka systemu i odpowiednio dostosować kod pod niego?
}

; Plik ini NIEMIECKI
[Sekcja 2]
Data=10.09.2011

i to samo tutaj, jak przekonwertować datę na domyślną datę dla każdej wersji językowej, tak abym mógł na niej operować (wyciągać dzień tygodnia, miesiąc, rok itp...). ?

0

ShortDateFormat (i podobne) + F1

0

To tylko przykład, ale na tej podstawie możesz chwilowo zmienić format daty krótkiej w systemie na taki w jakim masz zapisaną datę w swojej bazie, zrobić co trzeba i przywrócić format domyślny.

uses
 DateUtils, SysUtils;

function KonwertujDate(const Data: string): Integer;
var
 Format: string;
 Separ: char;
begin
 Separ  := DateSeparator;
 Format := ShortDateFormat;
 try
  DateSeparator   := '.';
  ShortDateFormat := 'dd.mm.yyyy';
  Result := DaysBetween(Now, StrToDate(Data));
 finally
  DateSeparator   := Separ;
  ShortDateFormat := Format;
 end;
end;

Ewentualnie skorzystaj z tej funkcji, ale musisz znać format daty z bazy:

{
When extracting data from text or other operating systems the format of date strings can vary dramatically.
Borland function StrToDateTime() converts a string to a TDateTime value, but it is limited to the fact
that the string parameter must be in the format of the current locale’s date/time format.

eg. "MM/DD/YY HH:MM:SS"

This is of little use when extracting dates such as ..

  1)  "Friday 18 October 2002 08:34am (45 secs)"
  2)  "20020431"
  3)  "12.Nov.03"
  4)  "14 Hour 31 Minute 25 Second 321 MSecs"

This function will evaluate a DateTime string in accordance to the DateTime specifier
format string supplied. The following specifiers are supported ...

dd    =  the day as a number with a leading zero or space (01-31).
ddd   =  the day as an abbreviation (Sun-Sat)
dddd  =  the day as a full name (Sunday-Saturday)
mm    =  the month as a number with a leading zero or space (01-12).
mmm   =  the month as an abbreviation (Jan-Dec)
mmmm  =  the month as a full name (January-December)
yy    =  the year as a two-digit number (00-99).
yyyy  =  the year as a four-digit number (0000-9999).
hh    =  the hour with a leading zero or space (00-23)
nn    =  the minute with a leading zero or space (00-59).
ss    =  the second with a leading zero or space (00-59).
zzz   =  the millisecond with a leading zero (000-999).
ampm  =  Specifies am or pm flag hours (0..12)
ap    =  Specifies a or p flag hours (0..12)

NOTE : One assumption I have to make is that DAYS, MONTHS,
            HOURS and MINUTES have a leading ZERO or
            SPACE (ie. are 2 chars long) and MILLISECONDS are 3
            chars long (ZERO or SPACE padded)

Using function

DateTimeStrEval(const DateTimeFormat: string; const DateTimeStr: string): TDateTime;

The above Examples (1..4) can be evaluated as ...
(Assume DT1 to DT3 equals example strings 1..4)

1)  DateTimeStrEval('dddd dd mmmm yyyy hh:nnampm (ss xxxx)',DT1);
2)  DateTimeStrEval('yyyymmdd',DT2);
3)  DateTimeStrEval('dd-mmm-yy',DT3);
4) DateTimeStrEval('hh xxxx nn xxxxxx ss xxxxxx zzz xxxxx',DT4);
}

uses
 DateUtils;

function DateTimeStrEval(const DateTimeFormat: string; const DateTimeStr: string): TDateTime;
const
 MiesiacePL: array[1..12] of string = ('STYCZNIA','LUTEGO','MARCA','KWIETNIA','MAJA','CZERWCA','LIPCA','SIERPNIA','WRZEŚNIA','PAŹDZIERNIKA','LISTOPADA','GRUDNIA');
 MiesiaceEN: array[1..12] of string = ('JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC');
var
 i, ii, iii, AmPm: SmallInt;
 Retvar: TDateTime;
 Tmp, Fmt, Data, Mask, Spec: string;
 Year, Month, Day, Hour, Minute, Second, MSec: Word;
begin
 Year   := 1;
 Month  := 1;
 Day    := 1;
 Hour   := 0;
 Minute := 0;
 Second := 0;
 MSec   := 0;
 Fmt    := UpperCase(DateTimeFormat);
 Data   := AnsiUpperCase(DateTimeStr);
 i    := 1;
 ii   := 0;
 Mask := '';
 AmPm := 0;

 while i < Length(Fmt) do
   begin
    if Fmt[i] in ['A','D','H','M','N','P','S','Y','Z'] then
      begin
       // Start of a date specifier
       Mask := Fmt[i];
       ii := i + 1;

       // Keep going till not valid specifier
       while True do
         begin
          if ii > Length(Fmt) then Break;

          Spec := Mask + Fmt[ii];

          if (Spec = 'DD') or (Spec = 'DDD') or (Spec = 'DDDD') or
             (Spec = 'MM') or (Spec = 'MMM') or (Spec = 'MMMM') or
             (Spec = 'YY') or (Spec = 'YYY') or (Spec = 'YYYY') or
             (Spec = 'HH') or (Spec = 'NN')  or (Spec = 'SS') or
             (Spec = 'ZZ') or (Spec = 'ZZZ') or
             (Spec = 'AP') or (Spec = 'AM')  or (Spec = 'AMP') or
             (Spec = 'AMPM') then
            begin
             Mask := Spec;
             Inc(ii);
            end
          else Break;
         end;
      end;

    // Got a valid specifier ? - evaluate it from data string
    if (Mask <> '') and (Length(Data) > 0) then
      begin
       // Day 1..31
       if Mask = 'DD' then
         begin
          Day := StrToIntDef(Trim(Copy(Data, 1, 2)), 0);
          Delete(Data, 1, 2);
         end
       else
       // Day Sun..Sat (Just remove from data string)
       if Mask = 'DDD' then Delete(Data, 1, 3)
       else
       // Day Sunday..Saturday (Just remove from data string LEN)
       if Mask = 'DDDD' then
         begin
          Tmp := Copy(Data, 1, 3);
          for iii := 1 to 7 do
            if Tmp = AnsiUpperCase(Copy(LongDayNames[iii], 1, 3)) then
              begin
               Delete(Data, 1, Length(LongDayNames[iii]));
               Break;
              end;
         end
       else
       // Month 1..12
       if Mask = 'MM' then
         begin
          Month := StrToIntDef(Trim(Copy(Data, 1, 2)), 0);
          Delete(Data, 1, 2);
         end
       else
       // Month Jan..Dec
       if Mask = 'MMM' then
         begin
          Tmp := Copy(Data, 1, 3);
          for iii := 1 to 12 do
            if Tmp = UpperCase(Copy(LongMonthNames[iii], 1, 3)) then
              begin
               Month := iii;
               Delete(Data, 1, 3);
               Break;
              end;
         end
       else
       // Month January..December
       if Mask = 'MMMM' then
         begin
          Tmp := Copy(Data, 1, 3);

          for iii := 1 to 12 do
            begin
             {Jeśli jest to zmodyfikowana forma miesięcy polskich}
             if Pos(MiesiacePL[iii], Data) <> 0 then LongMonthNames[iii] := MiesiacePL[iii]
             else
             {Jeśli jest to zmodyfikowana forma miesięcy amerykańskich}
             if Pos(MiesiaceEN[iii], Data) <> 0 then LongMonthNames[iii] := MiesiaceEN[iii];

             if Tmp = AnsiUpperCase(Copy(LongMonthNames[iii], 1, 3)) then
               begin
                Month := iii;
                Delete(Data, 1, Length(LongMonthNames[iii]));

                Break;
               end;
            end;
         end
       else
       // Year 2 Digit
       if Mask = 'YY' then
         begin
          Year := StrToIntDef(Copy(Data, 1, 2), 0);
          Delete(Data, 1, 2);
          if Year < TwoDigitYearCenturyWindow then Year := (YearOf(Date) div 100) * 100 + Year
          else Year := (YearOf(Date) div 100 - 1) * 100 + Year;
         end
       else
       // Year 4 Digit
       if Mask = 'YYYY' then
         begin
          Year := StrToIntDef(Copy(Data, 1, 4), 0);
          Delete(Data, 1, 4);
         end
       else
       // Hours
       if Mask = 'HH' then
         begin
          Hour := StrToIntDef(Trim(Copy(Data, 1, 2)), 0);
          Delete(Data, 1, 2);
         end
       else
       // Minutes
       if Mask = 'NN' then
         begin
          Minute := StrToIntDef(Trim(Copy(Data, 1, 2)), 0);
          Delete(Data, 1, 2);
         end
       else
       // Seconds
       if Mask = 'SS' then
         begin
          Second := StrToIntDef(Trim(Copy(Data, 1, 2)), 0);
          Delete(Data, 1, 2);
         end
       else
       // Milliseconds
       if (Mask = 'ZZ') or (Mask = 'ZZZ') then
         begin
          MSec := StrToIntDef(Trim(Copy(Data, 1, 3)), 0);
          Delete(Data, 1, 3);
         end
       else
       // AmPm A or P flag
       if Mask = 'AP' then
         begin
          if Data[1] = 'A' then AmPm := -1
          else AmPm := 1;
          Delete(Data, 1, 1);
         end
       else
       // AmPm AM or PM flag
       if (Mask = 'AM') or (Mask = 'AMP') or (Mask = 'AMPM') then
         begin
          if Copy(Data, 1, 2) = 'AM' then AmPm := -1
          else AmPm := 1;
          Delete(Data, 1, 2);
         end;

       Mask := '';
       i := ii;
      end
    else
      begin
       // Remove delimiter from data string
       if Length(Data) > 1 then Delete(Data, 1, 1);
       Inc(i);
      end;
   end;

 if AmPm = 1 then Hour := Hour + 12;
 if not TryEncodeDateTime(Year, Month, Day, Hour, Minute, Second, MSec, Retvar) then Retvar := 0.0;

 Result := Retvar;
end;
0

Dzieki za odpowiedzi, ale niestety, oba te sposoby nie za bardzo pasują... :/

Zastanawiam się, by zastosować, zmianę wyświetlania daty systemowej na format 'ROK-MIESCIAC-DZIEN', programowo na czas działania programu a pozniej przywrócić, tylko jak to zrobić ?

0

Ja nie wiem za bardzo w czym problem. Ale chyba najprościej było by zapisać Datę jako Integer czy tam Float bez czasu po przecinku (jest to wtedy liczba dni od jakiejś tam odległej daty z bodajże 19 wieku - dokładniej masz to opisane w Helpie od Delphi). A później już można ją przekonwertować.

Przykład zapisu:

  DatETimePicker1.Time := 0;
  DatETimePicker1.Kind := dtkDate;
  Edit1.Text := FloatToStr(DatETimePicker1.DateTime);

Przykład odczytu:

  DateTimePicker1.ShowCheckbox := True;
  DateTimePicker1.Date := StrToFloat(Edit1.Text);
  DateTimePicker1.Kind := dtkDate;
  DateTimePicker1.Time := 0;
  DateTimePicker1.ShowCheckbox := False;

Pokombinuj w ten sposób. Datę możesz formatować tak:

  Caption := FormatDateTime('DD,MM.YYYY', DateTimePicker1.Date);

O ile dobrze zrozumiałem Twój problem. Bo nie ma co kombinować z podmienianiem ustawień regionalnych Użytkownika tylko dopasować program tak, aby był uniwersalny w działaniu i tyle.

EDIT: ewentualnie jakbyś miał problem z czasem to również można się wspomóc takim zapisem jako Integer:

function Time2Secs(Time : TDateTime) : integer;
var
  T : LongInt;
begin
  T := (StrToInt(FormatDateTime('hh', Time)) * 3600)
    + (StrToInt(FormatDateTime('nn', Time)) * 60)
    + (StrToInt(FormatDateTime('ss', Time)));
  Result := T;
end;

{Funkcja konwertująca sekundy na string w formacie GG:MM:SS:}

function Secs2Time(Sec : Integer) : string;
var
  ZH, ZM, ZS : Integer;
begin
  if (Sec > 0) and (Sec < 24 * 60 * 60) then
  begin
    ZH := Sec div 3600;
    ZM := Sec div 60 - ZH * 60;
    ZS := Sec - (ZH * 3600 + ZM * 60);
    Result := Format('%0.2d:%0.2d:%0.2d', [ZH, ZM, ZS]);
  end
  else
  begin
    Result := Format('%0.2d:%0.2d:%0.2d', [0, 0, 0]);
  end;
end;
0

Problem polega na tym:

Komputer A:
Windows 7 - Wersja Polska
Format zapisywanej daty: rrrr-mm-dd

Komputer B:
Windows 7 - Wersja Niemiecka
Format zapisywanej daty: dd.mm.rrrr

W programie tworze baze danych pracownikow, oraz zapisuje do niej daty wykonania pracy na poszczególnych obiektach np.:

Komputer A - jan_kowalski.ini:

[Jan Kowalski]
Data wykonania=2011-09-11
Data wystawienia faktury=2011-09-25

Komputer B - jan_kowalski.ini:

[Jan Kowalski]
Data wykonania=11.09.2011
Data wystawienia faktury=25.09.2011

Teraz, gdy chcę wczytać dane pracownikow tej bazy z komputera A na komputerze B
To otrzymuję komunikat "Invalid type data", ponieważ ma ona już inny format.

Ogólnie to chcę zrobić bazę danych tak, aby można było ją przenosić na pendrive (z pracy do domu) i kontynuować pracę.

0
user322 napisał(a)

Zastanawiam się, by zastosować, zmianę wyświetlania daty systemowej na format 'ROK-MIESCIAC-DZIEN', programowo na czas działania programu a pozniej przywrócić, tylko jak to zrobić ?

ja cież prostytutka nie [CIACH!] - to już drugi w tym tygodniu, który nie potrafi czytać!!!!!! Przecież ci napisałem

Misiekd napisał(a)

ShortDateFormat (i podobne) + F1

A tak całkiem OT to DATĘ W BAZIE ZAPISUJE SIĘ JAKO DATĘ A NIE JAKO CIĄG ZNAKÓW wtedy nie ma problemu z formatem jej zapisu!!!! Data w Delphi to Double - zapisz double i nie będzie problemu

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