Gesagt getan, in Python und Java hat ChatGPT das für mich gemacht, in Lazarus habe ich dann selber. Dann wollte ich es portieren von Lazarus auf Turbo-Pascal und auch schauen, ob es Linux-fähig wäre.
Okay, ich habe viel probiert und gelernt, weiß jetzt was ein DOS-Timestamp ist und was ein Unix-Timestamp, habe viele Funktionen zum Erzeugen und Formatieren und Umrechnungen gemacht - mehr als ich eigentlich brauche für das Touch. Aber meine Zeit-Unit soll da umgebaut/erweitert werden, da die bisher eine alternative Zahl in Tausendstel-Sekunden benutzt.
Nun meine Fragen: es gelingt mir irgendwie nicht, den Unix-Timestamp zum Setzen/Lesen der Änderungszeit zu benutzen. Ich kann ihn berechnen, konvertieren aber weder lesen noch setzen. ZB Heute wird dann nach 2049 verschoben. Geht mit Pascal wirklich nur der DOS-Timestamp? Mit allen Einschränkungen, keine Sekundenbruchteile und sogar nur Rundung auf gerade Sekunden (2). Ich dachte, Python kann das, und zB der Totalcommander zeigt zumindestens ungerade Sekunden an.
Code: Alles auswählen
program Touch;
{$IFNDEF DOS}
{$MODE OBJFPC}
uses SysUtils, DateUtils, Dos, Stdio, Zeit, Watch
{$IFDEF UNIX} , BaseUnix {$ENDIF};
{$ELSE}
uses Dos, Stdio, Zeit, Watch;
{$ENDIF}
type
TTimestamp = {$IFDEF DOS} TDosTime {$ELSE} Card {$ENDIF};
procedure PrintHelp;
begin
WriteLn('Usage: touch [OPTIONS] <filename>');
WriteLn('Options:');
WriteLn(' -r <file> Set the timestamp of <filename> to that of <file>');
WriteLn(' -t <time> Set the timestamp of <filename> to the specified time (YYYYMMDDhhmmss)');
WriteLn(' -a Change only the access time');
WriteLn(' -m Change only the modification time');
WriteLn(' -h Show this help message');
Halt(0);
end;
procedure Abort(reason: String);
begin
Writeln(reason);
Halt(1);
end;
function GetFileTime(FileName: string): TTimestamp;
{$IFDEF DOS}
var
F: File;
DT: TDosTime;
begin
Assign(F, FileName);
{$I-} Reset(F); {$I+}
if IOResult <> 0 then begin
GetFileTime := -1;
Exit;
end;
GetFTime(F, DT);
Close(F);
GetFileTime := DT;
{$ELSE}
var
Info: SearchRec;
begin
FindFirst(FileName, faAnyFile, Info);
if DosError = 0 then begin
GetFileTime := TimeDos2Timestamp(Info.Time);
FindClose(Info);
end else
GetFileTime := -1;
{$ENDIF}
end;
procedure SetFileTime(FileName: string; TS: TTimestamp; ChangeAccess, ChangeModify: Boolean);
{$IFDEF UNIX}
var
UT: TUTimBuf;
begin
if ChangeAccess then begin
UT.actime := TS;
UT.modtime := TS;
FpUtime(FileName, @UT);
end;
{$ENDIF}
{$IFDEF DOS}
var
F: File;
begin
if ChangeModify then begin
Assign(F, FileName);
{$I-} Reset(F); {$I+}
if IOResult <> 0 then begin
Rewrite(F);
if IOResult <> 0 then Exit;
end;
SetFTime(F, TS);
Close(F);
end;
{$ELSE}
begin
if ChangeModify then
FileSetDate(FileName, TS);
{$ENDIF}
end;
function ParseDateTime(DateTimeStr: string): TTimestamp;
var
Year, Month, Day, Hour, Minute, Second: Integer;
TS: TTimestamp;
begin
TS := 0;
if Length(DateTimeStr) = 14 then begin
Year := Str2Card(Copy(DateTimeStr, 1, 4));
Month := Str2Card(Copy(DateTimeStr, 5, 2));
Day := Str2Card(Copy(DateTimeStr, 7, 2));
Hour := Str2Card(Copy(DateTimeStr, 9, 2));
Minute := Str2Card(Copy(DateTimeStr, 11, 2));
Second := Str2Card(Copy(DateTimeStr, 13, 2));
if (Year < 1980) or (Month < 1) or (Month > 12) or (Day < 1) or (Day > 31) then TS := -1;
case Month of
1, 3, 5, 7, 8, 10, 12: if Day > 31 then TS := -1;
4, 6, 9, 11: if Day > 30 then TS := -1;
2: if (IsLeapYear(Year) and (Day > 29)) or (Day > 28) then TS := -1;
end;
if (Hour < 0) or (Hour > 23) or (Minute < 0) or (Minute > 59) or
(Second < 0) or (Second > 59) then TS := -1;
end
else TS := -1;
if TS = 0 then TS :=
{$IFDEF DOS} DTValues2TimeDos (Year, Month, Day, Hour, Minute, Second);
{$ELSE} DTValues2Timestamp(Year, Month, Day, Hour, Minute, Second, 0);
{$ENDIF}
ParseDateTime := TS;
end;
procedure ShowTimeStamp(Kommentar: String; TS: TTimestamp);
begin
(*
Write(Kommentar, '(LongInt): ', TS);
Writeln(' (Date/Time): ', {$IFDEF DOS} FormatTimeDos {$ELSE} FormatTimestamp {$ENDIF} (TS));
*)
Writeln(Kommentar,' ', {$IFDEF DOS} FormatTimeDos {$ELSE} FormatTimestamp {$ENDIF} (TS));
end;
var
i: Integer;
FileName: string;
SourceFile: string;
Timestamp, Temp: TTimestamp;
ChangeAccess, ChangeModify: Boolean;
OptC: char;
OptS: string;
begin
if ParamCount = 0 then begin
PrintHelp;
Halt(1);
end;
ChangeAccess := False;
ChangeModify := False;
SourceFile := '';
Timestamp := {$IFDEF DOS} GetTimeDos {$ELSE} GetTimestamp {$ENDIF};
i := 1;
while i <= ParamCount do begin
OptS := Paramstr(i);
if OptS[1] <> '-'
then FileName := OptS
else begin
OptC := OptS[2];
case OptC of
'h' : PrintHelp;
'r' : begin
if i + 1 <= ParamCount then begin
SourceFile := ParamStr(i + 1);
Inc(i);
end
else Abort('Error: no reference file is given after -r');
Timestamp := GetFileTime(SourceFile);
if Timestamp <> -1
then ShowTimeStamp('reference timestamp: ', Timestamp)
else Abort('Error: no valid timestamp for reference file');
end;
't' : begin
if i + 1 <= ParamCount then begin
Temp := ParseDateTime(ParamStr(i + 1));
if Temp < 0 then
Abort('Error: timestamp given has no valid format ' + Paramstr(i + 1));
Timestamp := Temp;
Inc(i);
end
else Abort('Error: no timestamp is given after -t');
end;
'a' : ChangeAccess := True;
'm' : ChangeModify := True;
else Abort('Error: wrong parameter ' + Paramstr(i));
end;
end;
Inc(i);
end;
if FileName = '' then
Abort('Error: no file name is given');
if not ChangeAccess and not ChangeModify then begin
ChangeAccess := True;
ChangeModify := True;
end;
SetFileTime(FileName, Timestamp, ChangeAccess, ChangeModify);
Writeln('Timestamp: '+
{$IFDEF DOS} FormatTimeDos {$ELSE} FormatTimestamp {$ENDIF} (Timestamp) +
' for file "' + FileName + '" has been set.');
Readln;
end.
Code: Alles auswählen
unit watch;
{$IFNDEF DOS}
{$mode objfpc}{$H+}
{$ENDIF}
interface
uses Stdio;
type
TDosTime = LongInt;
function GetTimestamp: Card;
function DTValues2Timestamp(Year, Month, Day, Hour, Min, Sec, Sec100: Word): Card;
function FormatTimestamp(TS: Card): string;
function FormatDTValues(Year, Month, Day, Hour, Min, Sec, Sec100: Word): string;
procedure Timestamp2DTValues(TS: Card; var Year, Month, Day, Hour, Min, Sec, Sec100: Word);
function GetTimeDos: TDosTime;
function DTValues2TimeDos(Year, Month, Day, Hour, Min, Sec: Word): TDosTime;
function FormatTimeDos(DT: TDosTime): string;
procedure TimeDos2DTValues(DT: TDosTime; var Year, Month, Day, Hour, Min, Sec: Word);
function Timestamp2TimeDos(TS: Card): TDosTime;
function TimeDos2Timestamp(DT: TDosTime): Card;
function IsLeapYear(Year: Word): Boolean;
function GetCurrentYear: Word;
implementation
uses
Dos;
const
DaysInMonth: array[1..12] of Word = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
function IsLeapYear(Year: Word): Boolean;
begin
IsLeapYear := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
end;
procedure Timestamp2DTValues(TS: Card; var Year, Month, Day, Hour, Min, Sec, Sec100: Word);
var
DaysLeft: Card;
begin
DaysLeft := TS div 86400000;
TS := TS mod 86400000;
Year := 1970;
while DaysLeft >= (365 + Ord(IsLeapYear(Year))) do begin
Dec(DaysLeft, 365 + Ord(IsLeapYear(Year)));
Inc(Year);
end;
Month := 1;
while DaysLeft >= (DaysInMonth[Month] + Ord((Month = 2) and IsLeapYear(Year))) do begin
Dec(DaysLeft, DaysInMonth[Month] + Ord((Month = 2) and IsLeapYear(Year)));
Inc(Month);
end;
Day := DaysLeft + 1;
Hour := TS div 3600000;
TS := TS mod 3600000;
Min := TS div 60000;
TS := TS mod 60000;
Sec := TS div 1000;
Sec100 := (TS mod 1000) div 10;
end;
function DTValues2Timestamp(Year, Month, Day, Hour, Min, Sec, Sec100: Word): Card;
var
TotalDays: Card;
i: Integer;
begin
TotalDays := 0;
for i := 1970 to Year - 1 do
if IsLeapYear(i)
then Inc(TotalDays, 366)
else Inc(TotalDays, 365);
for i := 1 to Month - 1 do
Inc(TotalDays, DaysInMonth[i] + Ord((i = 2) and IsLeapYear(Year)));
Inc(TotalDays, Day - 1);
DTValues2Timestamp := TotalDays * 86400000 + Hour * 3600000 + Min * 60000 + Sec * 1000 + Sec100 * 10;
end;
function GetTimestamp: Card;
var
Year, Month, Day, Hour, Min, Sec, Sec100, Dummy: Word;
begin
GetDate(Year, Month, Day, Dummy);
GetTime(Hour, Min, Sec, Sec100);
GetTimestamp := DTValues2Timestamp(Year, Month, Day, Hour, Min, Sec, Sec100);
end;
function FormatDTValues(Year, Month, Day, Hour, Min, Sec, Sec100: Word): string;
begin
FormatDTValues :=
Str0Card(Day,2) + '.' +
Str0Card(Month,2) + '.' +
Str0Card(Year,2) + ' ' +
Str0Card(Hour,2) + ':' +
Str0Card(Min,2) + ':' +
Str0Card(Sec,2) + ',' +
Str0Card(Sec100,3);
end;
function FormatTimestamp(TS: Card): string;
var
Year, Month, Day, Hour, Min, Sec, Sec100: Word;
begin
Timestamp2DTValues(TS, Year, Month, Day, Hour, Min, Sec, Sec100);
FormatTimestamp := FormatDTValues(Year, Month, Day, Hour, Min, Sec, Sec100);
end;
function DTValues2TimeDos(Year, Month, Day, Hour, Min, Sec: Word): TDosTime;
begin
if Year < 1980 then Year := 1980; { DOS erlaubt keine Jahre vor 1980 }
DTValues2TimeDos :=
(LongInt(Year - 1980) shl 25) or { Jahr ab 1980 speichern (7 Bit) }
(LongInt(Month) shl 21) or { Monat (4 Bit) }
(LongInt(Day) shl 16) or { Tag (5 Bit) }
(LongInt(Hour) shl 11) or { Stunde (5 Bit) }
(LongInt(Min) shl 5) or { Minute (6 Bit) }
(LongInt(Sec div 2)); { Sekunde/2 (5 Bit) }
end;
function GetTimeDos: TDosTime;
var
Year, Month, Day, Dummy, Hour, Min, Sec: Word;
begin
GetDate(Year, Month, Day, Dummy);
GetTime(Hour, Min, Sec, Dummy);
GetTimeDos := DTValues2TimeDos(Year, Month, Day, Hour, Min, Sec);
end;
procedure TimeDos2DTValues(DT: TDosTime; var Year, Month, Day, Hour, Min, Sec: Word);
begin
Year := 1980 + (DT shr 25) and $7F;
Month := (DT shr 21) and $0F;
Day := (DT shr 16) and $1F;
Hour := (DT shr 11) and $1F;
Min := (DT shr 5) and $3F;
Sec := (DT and $1F) * 2;
end;
function FormatTimeDos(DT: TDosTime): string;
var
Hour, Min, Sec: Word;
Year, Month, Day: Word;
begin
TimeDos2DTValues(DT, Year, Month, Day, Hour, Min, Sec);
FormatTimeDos := FormatDTValues(Year, Month, Day, Hour, Min, Sec, 0);
end;
function Timestamp2TimeDos(TS: Card): TDosTime;
var
Year, Month, Day, Hour, Min, Sec, Sec100: Word;
begin
Timestamp2DTValues(TS, Year, Month, Day, Hour, Min, Sec, Sec100);
Timestamp2TimeDos := DTValues2TimeDos(Year, Month, Day, Hour, Min, Sec);
end;
function TimeDos2Timestamp(DT: TDosTime): Card;
var
Year, Month, Day, Hour, Min, Sec: Word;
begin
TimeDos2DTValues(DT, Year, Month, Day, Hour, Min, Sec);
TimeDos2Timestamp := DTValues2Timestamp(Year, Month, Day, Hour, Min, Sec, 0);
end;
function GetCurrentYear: Word;
var
Year, Dummy: Word;
begin
GetDate(Year, Dummy, Dummy, Dummy);
GetCurrentYear := Year;
end;
end.