Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision 1ab853969f4ab4bd3b894a43444959889f64873d)
+++ uspace/lib/c/generic/time.c	(revision 94e46c9512c28256bc6e96c5263cba46b43dc8c0)
@@ -59,4 +59,5 @@
 #define MINS_PER_HOUR  60
 #define SECS_PER_MIN   60
+#define USECS_PER_SEC  1000000
 #define MINS_PER_DAY   (MINS_PER_HOUR * HOURS_PER_DAY)
 #define SECS_PER_HOUR  (SECS_PER_MIN * MINS_PER_HOUR)
@@ -252,16 +253,17 @@
  * Optionally add specified amount of seconds.
  *
- * @param tm      Broken-down time to normalize.
- * @param sec_add Seconds to add.
+ * @param tm Broken-down time to normalize.
+ * @param tv Timeval to add.
  *
  * @return 0 on success, -1 on overflow
  *
  */
-static int normalize_time(struct tm *tm, time_t sec_add)
+static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
 {
 	// TODO: DST correction
 	
 	/* Set initial values. */
-	time_t sec = tm->tm_sec + sec_add;
+	time_t usec = tm->tm_usec + tv->tv_usec;
+	time_t sec = tm->tm_sec + tv->tv_sec;
 	time_t min = tm->tm_min;
 	time_t hour = tm->tm_hour;
@@ -271,4 +273,6 @@
 	
 	/* Adjust time. */
+	sec += floor_div(usec, USECS_PER_SEC);
+	usec = floor_mod(usec, USECS_PER_SEC);
 	min += floor_div(sec, SECS_PER_MIN);
 	sec = floor_mod(sec, SECS_PER_MIN);
@@ -319,4 +323,5 @@
 	
 	/* And put the values back to the struct. */
+	tm->tm_usec = (int) usec;
 	tm->tm_sec = (int) sec;
 	tm->tm_min = (int) min;
@@ -335,4 +340,15 @@
 }
 
+static int normalize_tm_time(struct tm *tm, time_t time)
+{
+	struct timeval tv = {
+		.tv_sec = time,
+		.tv_usec = 0
+	};
+
+	return normalize_tm_tv(tm, &tv);
+}
+
+
 /** Which day the week-based year starts on.
  *
@@ -442,4 +458,16 @@
 }
 
+static void tv_normalize(struct timeval *tv)
+{
+	while (tv->tv_usec > USECS_PER_SEC) {
+		tv->tv_sec++;
+		tv->tv_usec -= USECS_PER_SEC;
+	}
+	while (tv->tv_usec < 0) {
+		tv->tv_sec--;
+		tv->tv_usec += USECS_PER_SEC;
+	}
+}
+
 /** Add microseconds to given timeval.
  *
@@ -448,19 +476,27 @@
  *
  */
-void tv_add(struct timeval *tv, suseconds_t usecs)
-{
-	tv->tv_sec += usecs / 1000000;
-	tv->tv_usec += usecs % 1000000;
-	
-	if (tv->tv_usec > 1000000) {
-		tv->tv_sec++;
-		tv->tv_usec -= 1000000;
-	}
-}
-
-/** Subtract two timevals.
+void tv_add_diff(struct timeval *tv, suseconds_t usecs)
+{
+	tv->tv_sec += usecs / USECS_PER_SEC;
+	tv->tv_usec += usecs % USECS_PER_SEC;
+	tv_normalize(tv);
+}
+
+/** Add two timevals.
  *
  * @param tv1 First timeval.
  * @param tv2 Second timeval.
+ */
+void tv_add(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec += tv2->tv_sec;
+	tv1->tv_usec += tv2->tv_usec;
+	tv_normalize(tv1);
+}
+
+/** Subtract two timevals.
+ *
+ * @param tv1 First timeval.
+ * @param tv2 Second timeval.
  *
  * @return Difference between tv1 and tv2 (tv1 - tv2) in
@@ -468,8 +504,21 @@
  *
  */
-suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
+suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
 {
 	return (tv1->tv_usec - tv2->tv_usec) +
-	    ((tv1->tv_sec - tv2->tv_sec) * 1000000);
+	    ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC);
+}
+
+/** Subtract two timevals.
+ *
+ * @param tv1 First timeval.
+ * @param tv2 Second timeval.
+ *
+ */
+void tv_sub(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec -= tv2->tv_sec;
+	tv1->tv_usec -= tv2->tv_usec;
+	tv_normalize(tv1);
 }
 
@@ -573,5 +622,5 @@
 		goto fallback;
 	
-	tv->tv_usec = 0;
+	tv->tv_usec = time.tm_usec;
 	tv->tv_sec = mktime(&time);
 	
@@ -689,5 +738,5 @@
 	// TODO: detect overflow
 	
-	normalize_time(tm, 0);
+	normalize_tm_time(tm, 0);
 	return secs_since_epoch(tm);
 }
@@ -944,4 +993,5 @@
 	
 	/* Set result to epoch. */
+	result->tm_usec = 0;
 	result->tm_sec = 0;
 	result->tm_min = 0;
@@ -951,5 +1001,5 @@
 	result->tm_year = 70; /* 1970 */
 	
-	if (normalize_time(result, time) == -1)
+	if (normalize_tm_time(result, time) == -1)
 		return EOVERFLOW;
 	
@@ -1014,5 +1064,5 @@
  * Time is expressed relative to the user's specified timezone.
  *
- * @param timer  Time to convert.
+ * @param tv     Timeval to convert.
  * @param result Structure to store the result to.
  *
@@ -1020,5 +1070,5 @@
  *
  */
-int time_local2tm(const time_t time, struct tm *restrict result)
+int time_tv2tm(const struct timeval *tv, struct tm *restrict result)
 {
 	// TODO: Deal with timezones.
@@ -1026,4 +1076,5 @@
 	
 	/* Set result to epoch. */
+	result->tm_usec = 0;
 	result->tm_sec = 0;
 	result->tm_min = 0;
@@ -1033,8 +1084,28 @@
 	result->tm_year = 70; /* 1970 */
 	
-	if (normalize_time(result, time) == -1)
+	if (normalize_tm_tv(result, tv) == -1)
 		return EOVERFLOW;
 	
 	return EOK;
+}
+
+/** Converts a time value to a broken-down local time.
+ *
+ * Time is expressed relative to the user's specified timezone.
+ *
+ * @param timer  Time to convert.
+ * @param result Structure to store the result to.
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int time_local2tm(const time_t time, struct tm *restrict result)
+{
+	struct timeval tv = {
+		.tv_sec = time,
+		.tv_usec = 0
+	};
+
+	return time_tv2tm(&tv, result);
 }
 
