web-dev-qa-db-fra.com

Convertir une chaîne en tdateTime en fonction d'un format arbitraire

Y a-t-il un moyen à Delphi 5 pour convertir une chaîne en tdateTime où vous pouvez spécifier le format réel à utiliser?

Je travaille sur un jobprocessor, qui accepte les tâches de divers postes de travail. Les tâches ont une gamme de paramètres, dont certaines sont des dates, mais (malheureusement et hors de mon contrôle) sont passées en tant que chaînes. Étant donné que les travaux peuvent provenir de postes de travail différents, le format DateTime réel utilisé pour formater les dates comme une chaîne peut (et, bien sûr, réelle do ) .

Googling autour, les seules solutions rapides que j'ai trouvées étaient de changer sournoisement la variable ShortDateFormat et la restauré à sa valeur d'origine par la suite. Étant donné que ShortDateFormat est une variable globale et je travaille dans un environnement fileté la seule façon de fonctionner est de synchroniser tous les accès, ce qui est totalement inacceptable (et indûble).

Je pourrais copier le code de la bibliothèque de l'unité SysUtils dans mes propres méthodes et les modifier pour travailler avec un format spécifié au lieu des variables globales, mais je me demande simplement s'il y a quelque chose de plus adéquat que je manqué.

Cordialement, et merci d'avance,

Willem

MISE À JOUR

Pour la mettre plus succinctement:

J'ai besoin de quelque chose comme StrToDate (ou StrToDateTime), avec l'option ajoutée de la spécification du format exact nécessaire pour convertir la chaîne en tdateTime.

21
Willem van Rumpt

J'ai créé une telle routine pour l'unité de création de crétins de Freecal, et il convient de passer à autre chose, si le portage est nécessaire du tout.

Code:

http://svn.freecical.org/cgi-bin/viewvc.cgi/trunk/packages/rtl-objpas/src/inc/datetutil.inc?revision=30628&view=CO

(Le code est la dernière procédure (énorme) à la fin du fichier)

documentation:

http://www.freeScal.org/docs-html/rtl/datetutils/scandateTetime.html

Notez qu'il n'est pas une inverse complète du formatDateTime, et il a quelques extensions:

  • Un inverse de FormatDateTetime n'est pas 100% inverse, simplement parce que l'on peut mettre par ex. jetons de temps deux fois dans la chaîne de format et ScandateTime ne saurait pas le temps à choisir.

  • Les chaînes comme Hn ne peuvent pas être inversées en toute sécurité. Par exemple. 1: 2 (2 minutes après 1) fournit 12 qui est analysé à 12h00, puis manque des caractères pour la partie "n".

    • les caractères de fin sont ignorés.
    • pas de support pour les caractères de formatage de l'Est de l'Est, car ils sont uniquement des fenêtres.
    • aucun support de MBCS.
  • Extensions

    • # 9 mange WhitSpace.
    • whitSpace à la fin d'un motif est facultatif.
    • ? correspond à n'importe quel caractère.
    • Citez les caractères ci-dessus pour correspondre vraiment au caractère.

(Je crois que ces commentaires sont légèrement dépassés dans le sens du chapeau, certains appui asiatiques ont été ajoutés plus tard, mais je ne suis pas sûr)

8
Marco van de Voort

Utilisez VartodateTetime à la place. Il prend en charge de nombreux formats de date dans la chaîne et les convertit automatiquement.

var
  DateVal: TDateTime;
begin
  DateVal := VarToDateTime('23 Sep 2010');
  ShowMessage(DateToStr(DateVal));
end;

Je vois que vous utilisez Delphi 5. Certaines versions de Delphi devront ajouter des variantes à la clause utilisée; La plupart des versions ultérieures l'ajoutent pour vous. Je ne me souviens pas de quelle catégorie Delphi 5 est tombée dans.

30
Ken White

Les versions ultérieures de Delphi peuvent prendre un argument supplémentaire en Tformates sur les fonctions de conversion de chaîne. Les tformates sont une structure contenant les différentes variables mondiales de format (ShortDateDateFormat, LongdateFormat, etc.). Donc, vous pouvez remplacer cette valeur d'une manière thread-sûre et même pour un seul appel.

Je ne me souviens pas de la version de Delphi qui a été introduite, mais je suis sûr que c'était après Delphi 5.

Alors oui, autant que je sache, vous devez soit synchroniser tous les accès à ShortDateFormat, soit utiliser une fonction différente.

7
Ken Bourassa

Si vous voulez savoir comment cela a été résolu dans la suite de Delphi, vous pouvez jeter un coup d'œil à la source d'un peu plus moderne (ressemble à Delphi 6) sysutils.pas ici:

http://anygen.googlecome.com/.../sysutils.pas

Découvrez les versions surchargées de StrToDateTime qui prennent un paramètre TFormatSettings.

function StrToDateTime(const S: string;
  const FormatSettings: TFormatSettings): TDateTime; overload;
4

Utilisez la bibliothèque REGEXPR ( https://github.com/Masterandrey/tregexpr )

var
    RE: TRegExpr;

begin
    RE := TRegExpr.Create;
    try
        RE.Expression := '^(\d\d\d\d)/(\d\d)/(\d\d)T(\d\d):(\d\d):(\d\d)$';
        if RE.Exec( Value ) then
        begin
            try
                Result := EncodeDate( StrToInt( RE.Match[1] ),
                                      StrToInt( RE.Match[2] ),
                                      StrToInt( RE.Match[3] ) ) +
                          EncodeTime( StrToInt( RE.Match[4] ),
                                      StrToInt( RE.Match[5] ),
                                      StrToInt( RE.Match[6] ),
                                      0 )
            except
                raise EConvertError.Create( 'Invalid date-time: ' + Value )
            end
        end
        else
            raise EConvertError.Create( 'Bad format: ' + Value )
    finally
        RE.Free
    end
end;
1
Mads Boyd-Madsen

Je ne suis pas sûr de ce que vous voulez. Je n'utilise plus Delphi 5 mais je suis à peu près sûr que la fonction strtodateTetime existe. En utilisant, vous pouvez convertir une chaîne en TdateTime avec des paramètres de format. Ensuite, vous pouvez convertir une telle tdateTime en n'importe quel format à l'aide de FormatDateTime, ce qui vous permet d'utiliser n'importe quel format de date souhaité.

1
Eduardo Mauro

Je voudrais aller dans l'autre sens. Comme je le vois, vous avez environ deux options de ce que vous avez mentionné un vous-même

  • Ajustez le shortDateFormat et gardez tous les accès synchronisés.
  • Si vous connaissez le format des cordes, vous récitez (d'une manière ou d'une autre, vous aurez à)), juste -faire du jonglage de la chaîne pour d'abord obtenir vos chaînes dans votre courtedateFormat actuel. Après cela, convertissez la chaîne (jonglée) en un TDateTime.

Je me demande comment vous allez déterminer le format pour dire 04/05/2010.

program DateTimeConvert;
{$APPTYPE CONSOLE}
uses
  SysUtils;


function GetPart(const part, input, format: string): string;
var
  I: Integer;
begin
  for I := 1 to Length(format) do
    if Uppercase(format[I]) = Uppercase(part) then
      Result := Result + input[I];
end;

function GetDay(const input, format: string): string;
begin
  Result := GetPart('d', input, format);
  if Length(Result) = 1 then Result := SysUtils.Format('0%0:s', [Result]);
end;

function GetMonth(const input, format: string): string;
begin
  Result := GetPart('m', input, format);
  if Length(Result) = 1 then Result := SysUtils.Format('0%0:s', [Result]);
end;

function GetYear(const input, format: string): string;
begin
  Result := GetPart('y', input, format);
end;

function ConvertToMyLocalSettings(const input, format: string): string;
begin
  Result := SysUtils.Format('%0:s/%1:s/%2:s', [GetDay(input, format), GetMonth(input, format), GetYear(input, format)]);
end;

begin
  Writeln(ConvertToMyLocalSettings('05/04/2010', 'dd/mm/yyyy'));
  Writeln(ConvertToMyLocalSettings('05-04-2010', 'dd-mm-yyyy'));
  Writeln(ConvertToMyLocalSettings('5-4-2010', 'd-m-yyyy'));
  Writeln(ConvertToMyLocalSettings('4-5-2010', 'm-d-yyyy'));
  Writeln(ConvertToMyLocalSettings('4-05-2010', 'M-dd-yyyy'));
  Writeln(ConvertToMyLocalSettings('05/04/2010', 'dd/MM/yyyy'));
  Readln;
end.
0
Lieven Keersmaekers