Index: uspace/app/date/date.c
===================================================================
--- uspace/app/date/date.c	(revision 6a3808eaae144c8696d284cf2ae0335d51f453ea)
+++ uspace/app/date/date.c	(revision fa18523547f587da07046f2697155b9dae6897fa)
@@ -43,5 +43,10 @@
 static int read_time_from_arg(char *wdate, struct tm *t);
 static int read_num_from_str(char *str, size_t len, int *n);
+static int tm_sanity_check(struct tm *t);
+static bool is_leap_year(int year);
+
 static void usage(void);
+
+static int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 int
@@ -181,4 +186,10 @@
 		}
 
+		rc = tm_sanity_check(&t);
+		if (rc != EOK) {
+			printf(NAME ": error, invalid date/time\n");
+			goto exit;
+		}
+
 		rc = clock_dev_time_set(sess, &t);
 		if (rc != EOK) {
@@ -278,4 +289,60 @@
 }
 
+/** Check if the tm structure contains valid values
+ *
+ * @param t     The tm structure to check
+ *
+ * @return      EOK on success or EINVAL
+ */
+static int
+tm_sanity_check(struct tm *t)
+{
+	int ndays;
+
+	if (t->tm_sec < 0 || t->tm_sec > 59)
+		return EINVAL;
+	else if (t->tm_min < 0 || t->tm_min > 59)
+		return EINVAL;
+	else if (t->tm_hour < 0 || t->tm_hour > 23)
+		return EINVAL;
+	else if (t->tm_mday < 1 || t->tm_mday > 31)
+		return EINVAL;
+	else if (t->tm_mon < 0 || t->tm_mon > 11)
+		return EINVAL;
+	else if (t->tm_year < 0 || t->tm_year > 199)
+		return EINVAL;
+
+	if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
+		ndays = 29;
+	else
+		ndays = days_month[t->tm_mon];
+
+	if (t->tm_mday > ndays)
+		return EINVAL;
+
+	return EOK;
+}
+
+/** Check if a year is a leap year
+ *
+ * @param year   The year to check
+ *
+ * @return       true if it is a leap year, false otherwise
+ */
+static bool
+is_leap_year(int year)
+{
+	bool r = false;
+
+	if (year % 4 == 0) {
+		if (year % 100 == 0)
+			r = year % 400 == 0;
+		else
+			r = true;
+	}
+
+	return r;
+}
+
 static void
 usage(void)
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 6a3808eaae144c8696d284cf2ae0335d51f453ea)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision fa18523547f587da07046f2697155b9dae6897fa)
@@ -90,9 +90,5 @@
     ipc_callid_t callid, ipc_call_t *call);
 static int rtc_dev_remove(ddf_dev_t *dev);
-static int rtc_tm_sanity_check(struct tm *t, int epoch);
 static void rtc_register_write(rtc_t *rtc, int reg, int data);
-static bool is_leap_year(int year);
-
-static int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 static ddf_dev_ops_t rtc_dev_ops;
@@ -287,5 +283,4 @@
 	bool bcd_mode;
 	bool pm_mode = false;
-	int  epoch = 1900;
 	rtc_t *rtc = RTC_FROM_FNODE(fun);
 
@@ -352,5 +347,4 @@
 		 * RTC epoch is 2000.
 		 */
-		epoch = 2000;
 		t->tm_year += 100;
 	}
@@ -358,5 +352,9 @@
 	fibril_mutex_unlock(&rtc->mutex);
 
-	return rtc_tm_sanity_check(t, epoch);
+	time_t r = mktime(t);
+	if (r < 0)
+		return EINVAL;
+
+	return EOK;
 }
 
@@ -371,5 +369,4 @@
 rtc_time_set(ddf_fun_t *fun, struct tm *t)
 {
-	int  rc;
 	bool bcd_mode;
 	int  reg_b;
@@ -378,4 +375,7 @@
 	rtc_t *rtc = RTC_FROM_FNODE(fun);
 
+	if (mktime(t) < 0)
+		return EINVAL;
+
 	fibril_mutex_lock(&rtc->mutex);
 
@@ -386,8 +386,8 @@
 		epoch = 1900;
 
-	rc = rtc_tm_sanity_check(t, epoch);
-	if (rc != EOK) {
+	if (epoch == 2000 && t->tm_year < 100) {
+		/* Can't set a year before the epoch */
 		fibril_mutex_unlock(&rtc->mutex);
-		return rc;
+		return EINVAL;
 	}
 
@@ -442,64 +442,5 @@
 	fibril_mutex_unlock(&rtc->mutex);
 
-	return rc;
-}
-
-/** Check if the tm structure contains valid values
- *
- * @param t     The tm structure to check
- * @param epoch The RTC epoch year
- *
- * @return      EOK on success or EINVAL
- */
-static int
-rtc_tm_sanity_check(struct tm *t, int epoch)
-{
-	int ndays;
-
-	if (t->tm_sec < 0 || t->tm_sec > 59)
-		return EINVAL;
-	else if (t->tm_min < 0 || t->tm_min > 59)
-		return EINVAL;
-	else if (t->tm_hour < 0 || t->tm_hour > 23)
-		return EINVAL;
-	else if (t->tm_mday < 1 || t->tm_mday > 31)
-		return EINVAL;
-	else if (t->tm_mon < 0 || t->tm_mon > 11)
-		return EINVAL;
-	else if (epoch == 2000 && t->tm_year < 100)
-		return EINVAL;
-	else if (t->tm_year < 0 || t->tm_year > 199)
-		return EINVAL;
-
-	if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
-		ndays = 29;
-	else
-		ndays = days_month[t->tm_mon];
-
-	if (t->tm_mday > ndays)
-		return EINVAL;
-
 	return EOK;
-}
-
-/** Check if a year is a leap year
- *
- * @param year   The year to check
- *
- * @return       true if it is a leap year, false otherwise
- */
-static bool
-is_leap_year(int year)
-{
-	bool r = false;
-
-	if (year % 4 == 0) {
-		if (year % 100 == 0)
-			r = year % 400 == 0;
-		else
-			r = true;
-	}
-
-	return r;
 }
 
