Discussion:
Uhrzeit aus String erstellen und Differenzen bilden
(zu alt für eine Antwort)
Timo Kessler
2005-03-05 17:40:01 UTC
Permalink
Hallo,

ich habe hier zwei Uhrzeiten als String vorliegen, die ich voneinander
abziehen möchte. Das Ergebnis soll dann wieder ein String sein.

das hier ist die Ausgangszeit (die ms sind nicht wichtig und können
abgeschnitten werden, wenns ginge würde ich die aber auch gerne mit
beachten):

10:05:08,078

das hier muss abgezogen werden:

00:04:31

damit dann das hier raus kommen:

10:05:08 - 00:04:31 = 10:00:37

Wie mache ich das am besten?

Habe mich mal mit folgendem Code probiert, aber damit kann ich nur die
Uhrzeiten erstellen. Wie aber Differenz ausrechnen? Muss auch
funktionieren beim Überschreiten von Mitternacht / Tageswechsel.


String timestamp = "10:05:08";
String diffTime = "00:04:31";

SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
Date uhrzeit = format.parse(timestamp);
Date diff = format.parse(diffTime);

System.out.println("Uhrzeit: " + uhrzeit.toString());
System.out.println("Validierung: " + diff.toString());


-----------------------------


So nachdem ich keine funktionierende Lösung mit richtigen
Date/Time-Formaten finden konnte habe ich eine Lösung basierend auf der
reinen Stringzerlegung geschrieben. Nur irgendwie graut es mir vor deren
produktivem Einsatz ;-)
Das Format vom String mit z.B. "23:59:59" ist aber fest vorgegeben. Da
kann nciht ein anderes Zeitformat auftauchen. Also aus dieser Sicht
sollte meine Lösung schon sicher sein.


//kann keine Zeitdifferenz von ueber einem Tag berechnen
private String transformStartTime(String timeStamp, String val1)
{
String[] time = timeStamp.split(":");
String[] elapsed = val1.split(":");


final int secondsTimeStamp = Integer.parseInt(time[0]) * 3600 +
Integer.parseInt(time[1]) * 60 + Integer.parseInt(time[2]);
//System.out.println(secondsTimeStamp);

final int secondsVal1Start = Integer.parseInt(elapsed[0]) *
3600 + Integer.parseInt(elapsed[1]) * 60 + Integer.parseInt(elapsed[2]);
//System.out.println(secondsVal1Start);

int start = secondsTimeStamp - secondsVal1Start;

String returnString = null;


//Unterscheidung ob die neue Zeit negativ ist, wenn ja wurde
die 24h Schwelle ueberschritten
if(start > 0)
{
int hours = start / 3600;
start = start % 3600;
int minutes = start / 60;
start = start % 60; //enthaelt jetzt die restlichen Sekunden

if(hours < 10)
{
returnString = "0" + hours + ":";
}
else
{
returnString = hours + ":";
}

if(minutes < 10)
{
returnString = returnString + "0" + minutes + ":";
}
else
{
returnString = returnString + minutes + ":";
}

if(start < 10)
{
returnString = returnString + "0" + start;
}
else
{
returnString = returnString + start;
}

}
else if(start == 0)
{
returnString = "00:00:00";
}
else//Startzeitpunkt ist vor 00:00:00, Timestamp danach
{
System.out.println("kleiner Mitternacht");
start = Math.abs(start); //Sekunden vor Mitternacht

int hours = start / 3600;
start = start % 3600;
int minutes = start / 60;
start = start % 60; //enthaelt jetzt die restlichen Sekunden

//Endwerte
hours = 24 - hours;
minutes = 60 - minutes;
start = 60 - start;

if(hours < 10)
{
returnString = "0" + hours + ":";
}
else
{
returnString = hours + ":";
}

if(minutes < 10)
{
returnString = returnString + "0" + minutes + ":";
}
else
{
returnString = returnString + minutes + ":";
}

if(start < 10)
{
returnString = returnString + "0" + start;
}
else
{
returnString = returnString + start;
}


}

return returnString;

}


Gruß
Timo
Sascha Broich
2005-03-05 18:33:54 UTC
Permalink
Post by Timo Kessler
Hallo,
ich habe hier zwei Uhrzeiten als String vorliegen, die ich voneinander
abziehen möchte. Das Ergebnis soll dann wieder ein String sein.
das hier ist die Ausgangszeit (die ms sind nicht wichtig und können
abgeschnitten werden, wenns ginge würde ich die aber auch gerne mit
10:05:08,078
00:04:31
10:05:08 - 00:04:31 = 10:00:37
Wie mache ich das am besten?
public String getDifference(String first, String second)
{
// Parsen
SimpleDateFormat firstFormat=new SimpleDateFormat("hh:mm:ss,SSS");
SimpleDateFormat secondFormat=new SimpleDateFormat("hh:mm:ss");

long minuent=firstFormat.parse(first).getTime();
long subtrahent=secondFormat.parse(second).getTime();

// Zeitdiff in ms
long diff=minuent-subtrahent;

return(firstFormat.format(new Date(diff));
}

Wenn die Differenz auch negativ werden kann, dann nimm besser das hier:

int ms=diff % 1000;
diff/=1000;

int s=diff % 60;
diff/=60;

int min=diff % 60;
diff/=60;

int h=diff;



Sascha Broich
--
Schlage nie jemanden grundlos.
Ein Grund findet sich immer.
Frank Dreyer
2005-03-05 20:14:08 UTC
Permalink
Post by Sascha Broich
int ms=diff % 1000;
diff/=1000;
int s=diff % 60;
diff/=60;
int min=diff % 60;
diff/=60;
int h=diff;
...Oder einfach diff = Math.abs(diff)
Timo Kessler
2005-03-06 09:16:16 UTC
Permalink
Post by Sascha Broich
public String getDifference(String first, String second)
{
// Parsen
SimpleDateFormat firstFormat=new SimpleDateFormat("hh:mm:ss,SSS");
SimpleDateFormat secondFormat=new SimpleDateFormat("hh:mm:ss");
long minuent=firstFormat.parse(first).getTime();
long subtrahent=secondFormat.parse(second).getTime();
// Zeitdiff in ms
long diff=minuent-subtrahent;
return(firstFormat.format(new Date(diff));
}
das rechnet falsch. Nur der erste Wert ist bei mir eine Uhrzeit, der
zweite Wert ist eine reine Stunden/Minuten/Sekunden Anzahl. Also
vergangene Zeit, die von der richtigen Uhrzeit abgezogen werden soll.
Siehe mein Beispiel im Posting.


Gruß
Timo
Peter Büttner
2005-03-06 11:20:27 UTC
Permalink
Post by Timo Kessler
Post by Sascha Broich
public String getDifference(String first, String second)
{
// Parsen
SimpleDateFormat firstFormat=new SimpleDateFormat("hh:mm:ss,SSS");
SimpleDateFormat secondFormat=new SimpleDateFormat("hh:mm:ss");
long minuent=firstFormat.parse(first).getTime();
long subtrahent=secondFormat.parse(second).getTime();
// Zeitdiff in ms
long diff=minuent-subtrahent;
return(firstFormat.format(new Date(diff));
}
das rechnet falsch. Nur der erste Wert ist bei mir eine Uhrzeit, der
zweite Wert ist eine reine Stunden/Minuten/Sekunden Anzahl. Also
vergangene Zeit, die von der richtigen Uhrzeit abgezogen werden soll.
Siehe mein Beispiel im Posting.
Haste's probiert?

Das SimpleD... hat da die Eigenschaft zu grosse Teile per Übertrag
anzupassen, wenn man es nicht abstellt. Evtl ist der Unterschied zwischen
'h' und 'H' ein Problem gewesen?
Was die aber in die Quere kommen kann sind: Zeitzonen, DST,
Schaltsekunden. Das wurde hier schon öfters durchgekaut:-)
Ach ja, die Probleme tauchen schon beim parsen auf, also
SimpleDateFormat beaufsichtigen und/oder weglassen.

Weglassen
---------
Weglassen hast du in deinem Handmade Ansatz getan, den du schon mal
entscheidend verbessern würdest wenn du das 'muss die 0 davor' auslagern
tätest. returnString (was'n Name - ungarische Notation wiederauferstanden
als Zombie:-) anders benennen (ok sb ist auch nicht der hit) und einen
StringBuffer/Builder verwenden, ist auch leserlicher.
Das mit dem +- 24/60/Math.abs kann man auch weglassen. Ich nehme mal an das
"00:01:00" - "00:02:00" => "23:59:00"
werden soll? Siehe Code.
Den hab' ich mal umgebaut: du siehst das man das mit viel weniger Code
hinbekommt, ohne 'tolle Innereien' zu verwenden, einfach wiederkehrende
Teile auslagern. So wird es auch übersichtlich, und die Sonderfälle
fielen auch zusammen - sowas sieht man manchmal erst wenn es eben kürzer
wird, man kann die Strukturen besser erfassen.

Problem bleibt: hast du alles abgedeckt? was macht "00:12"? per DateFormat
kriegt man hier passende Exceptions.


Beaufsichtigen
--------------
Alternative, je nachdem wie groß die Zeiten sein können - tauchen
da auch mehrere Tage/Jahre auf? - ist eine passende Zeitzone zu verwenden.

TimeZone tz = TimeZone.getTimeZone("UTC");
firstFormat.setTimeZone(tz);

Wenn dann um den Bereich 1.1.1970 mit den verwendeten Zeitspannen
keine Anormalitäten in der Zeitrechnung auftreten ist's ok.
Aber wie gesagt aufpassen das die Zeiten nicht zu groß werden.

Die Lösung
----------
Nimm was anderes, fertiges, Joda Time wird oft empfohlen, da könnte
das bereits alles abgedeckt sein (eigenes Zeitspannensystem).



-------------------------------------------------------------------------
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class WasteOfTime {

public static void main(String[] args) throws Exception {
System.out.println(timeSub("23:12:2,1","123:0:0"));
System.out.println(timeSub("00:02:00,0", "00:01:00"));
System.out.println(timeSub("00:01:00,0", "00:01:00"));
System.out.println(timeSub("00:01:00,0", "00:02:00"));
System.out.println(timeSub("00:01:00,0", "240:00:00"));

System.out.println("-------------------------------");
System.out.println(transformStartTime("23:12:2","123:0:0"));
System.out.println(transformStartTime("00:02:00", "00:01:00"));
System.out.println(transformStartTime("00:01:00", "00:01:00"));
System.out.println(transformStartTime("00:01:00", "00:02:00"));
System.out.println(transformStartTime("00:01:00", "240:00:00"));
}
// --- per SimpleDateFormat
-----------------------------------------------
private final static SimpleDateFormat timeFormat = new
SimpleDateFormat("HH:mm:ss,SSS");
private final static SimpleDateFormat elapseFormat = new
SimpleDateFormat("HH:mm:ss");
private final static TimeZone tz = TimeZone.getTimeZone("UTC");
static{
timeFormat.setTimeZone(tz);
elapseFormat.setTimeZone(tz);
}
private static String timeSub(String time, String span) throws
ParseException {
long newTime = timeFormat.parse(time).getTime() -
elapseFormat.parse(span).getTime();
return (newTime/1000/60/60/24) + " days, " + timeFormat.format(new
Date(newTime));
}

// --- Handgemacht
----------------------------------------------------------
final static int SEC_IN_DAY = 24*3600;

private static int toInt(String s){return Integer.parseInt(s);}

private static int parseTime(String timeStamp) {
String[] time = timeStamp.split(":");
return toInt(time[0]) * 3600 + toInt(time[1]) * 60 + toInt(time[2]);
}

private static void appendPrefixed(StringBuffer sb, int i){
if(i<10)sb.append('0');
sb.append(i);
}

// kann keine Zeitdifferenz von ueber einem Tag berechnen
// PEB: doch, nun schon.
private static String transformStartTime(String timeStamp, String val1) {
StringBuffer sb = new StringBuffer();

int start = parseTime(timeStamp) - parseTime(val1);
// Unterscheidung ob die neue Zeit negativ ist, wenn ja wurde die 24h
// Schwelle ueberschritten
if(start<0)sb.append("kleiner Mitternacht-> ");

while (start < 0) start = (SEC_IN_DAY+ start)%SEC_IN_DAY; // optimize
here

appendPrefixed(sb,start / 3600);// hour
sb.append(':');
start = start % 3600;
appendPrefixed(sb,start / 60);// minutes
sb.append(':');
start = start % 60;
appendPrefixed(sb,start);// seconds
return sb.toString();
}
}


Grüße
Peter - Sonntagmorgen, nix zu tun
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Timo Kessler
2005-03-06 19:43:05 UTC
Permalink
Post by Peter Büttner
Post by Timo Kessler
Post by Sascha Broich
public String getDifference(String first, String second)
{
// Parsen
SimpleDateFormat firstFormat=new SimpleDateFormat("hh:mm:ss,SSS");
SimpleDateFormat secondFormat=new SimpleDateFormat("hh:mm:ss");
long minuent=firstFormat.parse(first).getTime();
long subtrahent=secondFormat.parse(second).getTime();
// Zeitdiff in ms
long diff=minuent-subtrahent;
return(firstFormat.format(new Date(diff));
}
das rechnet falsch. Nur der erste Wert ist bei mir eine Uhrzeit, der
zweite Wert ist eine reine Stunden/Minuten/Sekunden Anzahl. Also
vergangene Zeit, die von der richtigen Uhrzeit abgezogen werden soll.
Siehe mein Beispiel im Posting.
Haste's probiert?
ja ich hatte es probiert....nur irgendwie glaube ich inzwischen dass es
doch funzt (oder zumindest funzen könnte ;-) ) und ich einen
gedanklichen Fehler hatte.
Muss das alles nochmal ganz in Ruhe durchtesten und auf Papier
nachvollziehen. Aber da habe ich heute keinen Nerv mehr zu. Werde ich
morgen früh machen wenn ich wieder munter bin ;-)
Post by Peter Büttner
}
// --- per SimpleDateFormat
-----------------------------------------------
private final static SimpleDateFormat timeFormat = new
SimpleDateFormat("HH:mm:ss,SSS");
private final static SimpleDateFormat elapseFormat = new
SimpleDateFormat("HH:mm:ss");
private final static TimeZone tz = TimeZone.getTimeZone("UTC");
static{
timeFormat.setTimeZone(tz);
elapseFormat.setTimeZone(tz);
}
private static String timeSub(String time, String span) throws
ParseException {
long newTime = timeFormat.parse(time).getTime() -
elapseFormat.parse(span).getTime();
return (newTime/1000/60/60/24) + " days, " + timeFormat.format(new
Date(newTime));
}
Danke für diesen Code. So auf den ersten Blick und Minitest würde ich
sagen der passt für mich. Werde das aber noch ausführlich testen, damit
auch wirklich alles passt.


Nochmals vielen Dank für deine großartige Mühe. Finde ich spitze von
dir, dass du dir solche Mühe gegeben hast und so viel Code gepostet hast
:):)

Gruß
Timo

Loading...