Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Υπολογισμος χρόνου

Îåêßíçóå áðü ôï ìÝëïò kallileo. Τελευταία δημοσίευση από το μέλος KelMan στις 17-10-2007, 00:00. Υπάρχουν 9 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  16-10-2007, 15:01 36317

    Υπολογισμος χρόνου

    Έχω το παρακατω εναν πινακα που αντιστοιχει σε κατασταση ενος διακοπτη:

    Con DateTime
    0 28-5-2007 10:22:34
    1 28-5-2007 11:35:04
    0 28-5-2007 13:25:30
    1 28-5-2007 17:45:56
    0 28-5-2007 18:33:01
    1 28-5-2007 23:29:34

    Θελω να υπολογισω το συναλικο χρονο που ηταν ο διακοπτη σε κατασταση 1.
    Δηλαδη θα πρεπει να υπολογιζω τον χρονο που παει απο 0 σε 1. Ο χρονος απο 1-0 δεν πρεπει να υπολογιζεται.
    Πως θα ηταν σωστο να το φτιαξω?
    Αν υπολογισω το ολικο χρόνο και αφαιρεσω απο αυτον την κατασταση που ο διακοπτης ηταν κλειστος δηλαδη τον χρονο απο 0 σε 1.

    Καμια ιδεα για το πως μπορω να κανω πραξεις με μεταβλητες Date(28-5-2007 10:22:34) ωστε να μου βγαζει το αποτελεσμα σε ωρες?
  •  16-10-2007, 15:16 36318 σε απάντηση της 36317

    Απ: Υπολογισμος χρόνου

    Θες να κάνεις τον υπολογισμό με SQL queries ή να φέρεις τα data μέσα στην εφαρμογή σου και να τα χειριστείς με κώδικα VB.NET/C# ?


    Vir prudens non contra ventum mingit
  •  16-10-2007, 15:41 36321 σε απάντηση της 36318

    Απ: Υπολογισμος χρόνου

    Βασικα αυτο σκεφτομουν αλλα δεν ξερω αν γινεται με SQL.Ή τουλαχιστο οι γνωσεις μου δεν φτανουν σε αυτο σημειο. Εγω ελεγα να τα διαβασω π.χ σε ενα πινακα και μετα μεσω C# να κανω τους υπολογισμους.
    Δεν θα ειναι λιγο πολυπλοκα τα queries? Δηλαδη πως θα μπορουσα να βαλω σαν συνθηκη μεσα στο query για να ξεχωρισω το 1 σε 0 απο τον 0 σε 1?
  •  16-10-2007, 15:56 36322 σε απάντηση της 36317

    Απ: Υπολογισμος χρόνου

    Με το κλασσικό τρόπο τα βάζεις σε ένα loop και το τρέχεις ανα δύο.( Δηλαδή μόλις ξαναβρεις 0 κάνεις τις πράξεις σου )
    Χρησιμοποιείς την DateDiff (microsoft.VisualBasic.DateDiff) και παίρνεις το αποτέλεσμα σου το οποίο το κρατάς σε μια μεταβλητή και το προσθέτεις συνέχεια.

    Πάντως για μένα:  Kάθε φορά που ενημερώνεται ο παραπάνω πίνακας με ένα Trigger ενημέρωνε και ένα πεδίο δίπλα 'χρόνος λειτουργίας', ώστε με ένα sum να το έχεις έτοιμο.

    Manos
  •  16-10-2007, 16:11 36323 σε απάντηση της 36322

    Απ: Υπολογισμος χρόνου

    OK. Αυτο με το loop κατανοητο.

    Αυτο ομως με το πεδιο 'χρονος λειτουργιας' οχι τοσο πολυ. Πως θα υπολογιζεται ο αυτο ο χρονος λειτουργιας?
  •  16-10-2007, 16:59 36324 σε απάντηση της 36323

    Απ: Υπολογισμος χρόνου

    kallileo:
    Αυτο ομως με το πεδιο 'χρονος λειτουργιας' οχι τοσο πολυ. Πως θα υπολογιζεται ο αυτο ο χρονος λειτουργιας?


    Θα φτιάξεις και ένα άλλο πεδίο στον πίνακα σου πχ WorktimeFld. Καί είτε με Trigger στο on insert (για πιο γρήγορα) ή από τον κώδικά που κάνεις insert στο πίνακα θα ενημερώνεις αυτό το πεδίο ως εξής:
    Αν είναι το Con 1  τότε με dateDiff θα βρίσκεις  πόσο χρόνος πέρασε από το τελευταίο 0 και θα το βάζεις στο πεδίο . Αλλιώς θα βάζεις 0. Έτσι όταν θέλεις να δεις πόσος χρόνος δούλεψε από έως μια ημερομηνία με ένα απλό sum θα το βρίσκεις εύκολα και κυρίως πολύ γρήγορα. Ειδικά αν έχεις index στις ημερομηνίες.

    Σορυ που δεν τα γράφω αναλυτικά αλλά βιάζομαι να παραδώσω κάτιTime

    Manos
  •  16-10-2007, 21:40 36333 σε απάντηση της 36324

    Απ: Υπολογισμος χρόνου

    {
    SqlConnection conn = new SqlConnection("Data Source=(local)\\SQLEXPRESS;Initial Catalog=opc;Integrated Security=True");
    conn.Open();

    SqlCommand selCmd = new SqlCommand("SELECT COUNT(*) FROM data WHERE timestamp>@date1 AND timestamp

    SqlParameter param1 = new SqlParameter();
    SqlParameter param2 = new SqlParameter();
    param1.ParameterName = "@date1";
    param1.Value = TextBox1.Text;
    selCmd.Parameters.Add(param1);

    param2.ParameterName = "@date2";
    param2.Value = TextBox2.Text;
    selCmd.Parameters.Add(param2);


    int count = (int)selCmd.ExecuteScalar();
    Label1.Text = count.ToString();
    conn.Close();
    }

    Εδω προσπαθώντας να μετρήσω τις γραμμές παίρνω το εξης σφαλμα:

    Arithmetic overflow error converting expression to data type datetime.

    στην γραμμη int count = (int)selCmd.ExecuteScalar();

    Επισης για καποιο λογο ενω εκανα επικολληση ολο τον κωδικα δεν δειχνει την SQL Query ολοκληρη.
  •  16-10-2007, 23:51 36336 σε απάντηση της 36317

    Απ: Υπολογισμος χρόνου

    Αν θες να χρησιμοποιήσεις C# ή VB.NEΤ, ο τύπος DateTime έχει την Subtract και operator - που θα σου επιστρέψουν το διάστημα μεταξύ δύο DateTime σε μορφή TimeSpan. H TimeSpan έχει το property TotalHours το οποίο επιστρέφει τις ώρες σε δεκαδικό. Ο παρακάτω κώδικας διαβάζει τις τιμές και υπολογίζει τη διαφορά:

    using (SqlConnection connection = new SqlConnection(Settings.Default.ConnectionString))
    {
        SqlCommand cmd=new SqlCommand("select con,time from dbo.times order by time asc",connection);
        connection.Open();
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            int oldCon=-1;
            DateTime oldTime=DateTime.MinValue;
            while (reader.Read())
            {
                int con=reader.GetInt32(0);
                DateTime time=reader.GetDateTime(1);
                if (oldCon == 0 && con == 1)
                {
                    Console.WriteLine(time.Subtract(oldTime).TotalHours);
                }
                oldCon = con;
                oldTime = time;
            }
        }
        connection.Close();
    }

    Ο κώδικας αυτός διαβάζει τις γραμμές με χρονολογική σειρά. Για κάθε γραμμή συγκρίνει την τιμή του con με την τιμή της προηγούμενης γραμής η οποία έχει αποθηκευθεί στην μεταβλητή oldCon. Αν η τρέχουσα τιμή ήταν 0 και η τωρινή 1, υπολογίζετη διαφορά τους σε ώρες και στέλνει το αποτέλεσμα στην κονσόλα.

    Στον SQL Server 2005 μπορείς να πάρεις το αποτέλεσμα με το παρακάτω query:

    with timesRN as
    (
        select Con, time,
            row_number() over (partition by Con order by time) as rn
        from dbo.times
    )
    select
        cur.Con, cur.time,
        prev.Con, prev.time,
        datediff(mi,prev.time,cur.time)/60.0 as hours
    from timesRN cur
        left outer join timesRN prev
        on cur.rn=prev.rn and cur.Con=1 and prev.Con=0
    where not prev.rn is null

    Το παραπάνω query βασίζεται στο ότι ένα 0 ακολουθείται πάντα από ένα 1. Έτσι, το πρώτο 0 ακολουθείται από το πρώτο 1, το δεύτερο 0 από το δεύτερο 2 κλπ. Το With TimesRN χρησιμοποιεί για να προσθέσει ένα αύξοντα αριθμό ξεχωριστά στις γραμμές με 0 και 1. Μετά, το join συνδυάζει τις γραμμές οι οποίες έχουν το ίδιο RowNumber (RN) αλλά η πρώτη έχει τιμή 1 και η δεύτερη τιμή 0. Τέλος, το not prev.rn is null αφαιρεί όσες εγγραφές δεν έχουν αντίστοιχες προηγούμενες τιμές. Η datediff επιστρέφει τη διαφορά μεαξύ των δύο γραμμών σε λεπτά. Θα μπορούσα να βάλω HH αν ήθελα να πάρω τις ώρες σε ακέραιο αριθμό.

    Το καλό με τον κώδικα είναι ότι διαβάζει τις τιμές μόνο μία φορά. Το καλό με το query είναι ότι μπορείς να το χρησιμοποιήσεις και σε άλλα queries.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  16-10-2007, 23:55 36337 σε απάντηση της 36333

    Απ: Υπολογισμος χρόνου

    Μια εναλλακτική λύση που βασίζεται σε TSQL query. Πάμε βήμα-βήμα:

     

    Ας υποθέσουμε ότι ο πίνακάς μας είναι ο παρακάτω:

     

    table switch(Con int, Dt DateTime)

     

    και τα περιεχόμενα είναι αυτά που περιγράφονται στο πρώτο post. Αυτό που μπορούμε να κάνουμε είναι να θεωρήσουμε ότι έχουμε δύο πίνακες, τον s0 που έχει όλα τα OFF και τον s1 που έχει όλα τα ON.

     

    Ας εκτελέσουμε τα παρακάτω:

     

    SELECT  *

    FROM    switch

    WHERE   con = 0

    SELECT  *

    FROM    switch

    WHERE   con = 1

     

    Παρατηρούμε ότι τα αποτελέσματα είναι τα παρακάτω:

     

    Con         Dt

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

    0           2007-05-28 10:22:34.000

    0           2007-05-28 13:25:30.000

    0           2007-05-28 18:33:01.000

     

    (3 row(s) affected)

     

    Con         Dt

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

    1           2007-05-28 11:35:04.000

    1           2007-05-28 17:45:56.000

    1           2007-05-28 23:29:34.000

     

    (3 row(s) affected)

     

     

    Μπορούμε να κάνουμε join τους δύο πίνακες κάπως έτσι:

     

    SELECT s0.*, s1.* FROM

    (SELECT * FROM switch

    WHERE con=0) s0 INNER JOIN (

    SELECT * FROM switch

    WHERE con=1) s1 ON s0.dt<s1.dt

     

    Το πρόβλημα όπως φαίνεται είναι ότι στο ON clause δεν μπορούμε να έχουμε τελεστή ισότητας καθώς δεν υπάρχουν κοινά πεδία, ωστόσο τίποτα δεν μας εμποδίζει να χρησιμοποιήσουμε τους τελεστές όπως φαίνεται παραπάνω. Το αποτέλεσμα που μας δίνει αυτό το query είναι:

     

    Con         Dt                      Con         Dt

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

    0           2007-05-28 10:22:34.000 1           2007-05-28 11:35:04.000

    0           2007-05-28 10:22:34.000 1           2007-05-28 17:45:56.000

    0           2007-05-28 13:25:30.000 1           2007-05-28 17:45:56.000

    0           2007-05-28 10:22:34.000 1           2007-05-28 23:29:34.000

    0           2007-05-28 13:25:30.000 1           2007-05-28 23:29:34.000

    0           2007-05-28 18:33:01.000 1           2007-05-28 23:29:34.000

     

    Άρα αυτό που έχουμε πετύχει προς το παρόν είναι να βάλουμε σε μία γραμμή μαζί τις τιμές έναρξης και λήξης ώστε να μπορέσουμε στη συνέχεια να κάνουμε υπολογισμούς. Αυτό που μένει είναι να ξεφορτωθούμε τις γραμμές που δεν μας κάνουν. Για παράδειγμα, η έναρξη στις 10:22 εμφανίζεται με λήξη στις 11:35, 17:45 και 23:29. Εμείς θέλουμε να κρατήσουμε την εγγύτερη τιμή, αυτήν που εμφανίστηκε πρώτη, δηλαδή την ελάχιστη από τις τρεις. Θα πρέπει λοιπόν να βάλουμε ένα min aggregation πάνω στο πεδίο της λήξης, που σημαίνει ότι πρέπει τα υπόλοιπα πεδία να μπουν σε group by. Έτσι, τελικά το query μας γίνεται κάπως έτσι:

     

    SELECT s0.dt start, MIN(s1.dt) finish, DATEDIFF(ss,s0.dt,MIN(s1.dt)) secs FROM

    (SELECT * FROM switch

    WHERE con=0) s0 INNER JOIN (

    SELECT * FROM switch

    WHERE con=1) s1 ON s0.dt<s1.dt

    GROUP BY s0.dt

     

    Που μας δίνει τα παρακάτω αποτελέσματα:

     

    start                   finish                  secs

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

    2007-05-28 10:22:34.000 2007-05-28 11:35:04.000 4350

    2007-05-28 13:25:30.000 2007-05-28 17:45:56.000 15626

    2007-05-28 18:33:01.000 2007-05-28 23:29:34.000 17793

     

     


    Vir prudens non contra ventum mingit
  •  17-10-2007, 00:00 36338 σε απάντηση της 36337

    Απ: Υπολογισμος χρόνου

    Χε χε χε... Είδα την απάντηση σου Παναγιώτη αφού έκανα post την δική μου...

    Ορίστε, έχεις πλέον τρεις λύσεις να διαλέξεις!


    Vir prudens non contra ventum mingit
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems