diff --git a/config.go b/config.go
index 465e659..6a0b921 100644
--- a/config.go
+++ b/config.go
@@ -3,23 +3,27 @@ package main
 const (
 	PORT = "8080"
 
-	DB_IP             = "127.0.0.1"
-	DB_NAME           = "trantor"
-	META_COLL         = "meta"
-	BOOKS_COLL        = "books"
-	TAGS_COLL         = "tags"
-	DAILY_VISITS_COLL = "visits.daily"
-	USERS_COLL        = "users"
-	STATS_COLL        = "statistics"
-	FS_BOOKS          = "fs_books"
-	FS_IMGS           = "fs_imgs"
+	DB_IP               = "127.0.0.1"
+	DB_NAME             = "trantor"
+	META_COLL           = "meta"
+	BOOKS_COLL          = "books"
+	TAGS_COLL           = "tags"
+	HOURLY_VISITS_COLL  = "visits.hourly"
+	DAILY_VISITS_COLL   = "visits.daily"
+	MONTHLY_VISITS_COLL = "visits.monthly"
+	USERS_COLL          = "users"
+	STATS_COLL          = "statistics"
+	FS_BOOKS            = "fs_books"
+	FS_IMGS             = "fs_imgs"
 
-	PASS_SALT            = "ImperialLibSalt"
-	MINUTES_UPDATE_TAGS  = 10
-	MINUTES_UPDATE_DAILY = 60 * 12
-	TAGS_DISPLAY         = 50
-	SEARCH_ITEMS_PAGE    = 20
-	NEW_ITEMS_PAGE       = 50
+	PASS_SALT              = "ImperialLibSalt"
+	MINUTES_UPDATE_TAGS    = 10
+	MINUTES_UPDATE_HOURLY  = 30
+	MINUTES_UPDATE_DAILY   = 60 * 12
+	MINUTES_UPDATE_MONTHLY = 60 * 24
+	TAGS_DISPLAY           = 50
+	SEARCH_ITEMS_PAGE      = 20
+	NEW_ITEMS_PAGE         = 50
 
 	TEMPLATE_PATH = "templates/"
 	CSS_PATH      = "css/"
diff --git a/database.go b/database.go
index 9a8fa98..9789a32 100644
--- a/database.go
+++ b/database.go
@@ -191,6 +191,14 @@ type Visits struct {
 	Count int   "value"
 }
 
+func (d *DB) GetHourVisits(start time.Time) ([]Visits, error) {
+	return d.mr.GetHourVisits(start, d.stats)
+}
+
 func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
 	return d.mr.GetDayVisits(start, d.stats)
 }
+
+func (d *DB) GetMonthVisits(start time.Time) ([]Visits, error) {
+	return d.mr.GetMonthVisits(start, d.stats)
+}
diff --git a/mapreduce.go b/mapreduce.go
index d46c8c3..9462806 100644
--- a/mapreduce.go
+++ b/mapreduce.go
@@ -7,16 +7,20 @@ import (
 )
 
 type MR struct {
-	meta  *mgo.Collection
-	tags  *mgo.Collection
-	daily *mgo.Collection
+	meta    *mgo.Collection
+	tags    *mgo.Collection
+	hourly  *mgo.Collection
+	daily   *mgo.Collection
+	monthly *mgo.Collection
 }
 
 func NewMR(database *mgo.Database) *MR {
 	m := new(MR)
 	m.meta = database.C(META_COLL)
 	m.tags = database.C(TAGS_COLL)
+	m.hourly = database.C(HOURLY_VISITS_COLL)
 	m.daily = database.C(DAILY_VISITS_COLL)
+	m.monthly = database.C(MONTHLY_VISITS_COLL)
 	return m
 }
 
@@ -54,15 +58,41 @@ func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) {
 	return tags, nil
 }
 
+func (m *MR) GetHourVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
+	if m.isOutdated(HOURLY_VISITS_COLL, MINUTES_UPDATE_HOURLY) {
+		var mr mgo.MapReduce
+		mr.Map = `function() {
+		              var day = Date.UTC(this.date.getUTCFullYear(),
+		                                 this.date.getUTCMonth(),
+		                                 this.date.getUTCDate(),
+	                                         this.date.getUTCHours());
+		              emit(day, 1);
+		          }`
+		mr.Reduce = `function(date, vals) {
+				 var count = 0;
+				 vals.forEach(function(v) { count += v; });
+				 return count;
+			     }`
+		err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, HOURLY_VISITS_COLL)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	var result []Visits
+	err := m.hourly.Find(nil).All(&result)
+	return result, err
+}
+
 func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
 	if m.isOutdated(DAILY_VISITS_COLL, MINUTES_UPDATE_DAILY) {
 		var mr mgo.MapReduce
 		mr.Map = `function() {
-			      var day = Date.UTC(this.date.getFullYear(),
-						 this.date.getMonth(),
-						 this.date.getDate());
-			      emit(day, 1);
-			  }`
+		              var day = Date.UTC(this.date.getUTCFullYear(),
+		                                 this.date.getUTCMonth(),
+		                                 this.date.getUTCDate());
+		              emit(day, 1);
+		          }`
 		mr.Reduce = `function(date, vals) {
 				 var count = 0;
 				 vals.forEach(function(v) { count += v; });
@@ -79,6 +109,30 @@ func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits,
 	return result, err
 }
 
+func (m *MR) GetMonthVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
+	if m.isOutdated(MONTHLY_VISITS_COLL, MINUTES_UPDATE_MONTHLY) {
+		var mr mgo.MapReduce
+		mr.Map = `function() {
+		              var day = Date.UTC(this.date.getUTCFullYear(),
+		                                 this.date.getUTCMonth());
+		              emit(day, 1);
+		          }`
+		mr.Reduce = `function(date, vals) {
+				 var count = 0;
+				 vals.forEach(function(v) { count += v; });
+				 return count;
+			     }`
+		err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, MONTHLY_VISITS_COLL)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	var result []Visits
+	err := m.monthly.Find(nil).All(&result)
+	return result, err
+}
+
 func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection, storeColl string) error {
 	_, err := m.meta.RemoveAll(bson.M{"type": storeColl})
 	if err != nil {
diff --git a/stats.go b/stats.go
index b9e8d23..c167888 100644
--- a/stats.go
+++ b/stats.go
@@ -47,14 +47,18 @@ func statsWorker() {
 func statsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
 	var data statsData
 	data.S = GetStatus(w, r)
+	data.Hourly = getHourlyVisits()
 	data.Daily = getDailyVisits()
+	data.Monthly = getMonthlyVisits()
 
 	loadTemplate(w, "stats", data)
 }
 
 type statsData struct {
-	S     Status
-	Daily []visitData
+	S       Status
+	Hourly  []visitData
+	Daily   []visitData
+	Monthly []visitData
 }
 
 type visitData struct {
@@ -62,26 +66,52 @@ type visitData struct {
 	Count int
 }
 
+func getHourlyVisits() []visitData {
+	const numDays = 2.5
+	var visits []visitData
+
+	start := time.Now().UTC().Add(-numDays * 24 * time.Hour)
+	visit, _ := db.GetHourVisits(start)
+	for _, v := range visit {
+		var elem visitData
+		hour := time.Unix(v.Date/1000, 0).UTC().Hour()
+		elem.Label = strconv.Itoa(hour + 1)
+		elem.Count = v.Count
+		visits = append(visits, elem)
+	}
+
+	return visits
+}
+
 func getDailyVisits() []visitData {
 	const numDays = 30
-	visits := make([]visitData, numDays)
+	var visits []visitData
 
-	start := time.Now().Add(-numDays * 24 * time.Hour).Truncate(24 * time.Hour)
+	start := time.Now().UTC().Add(-numDays * 24 * time.Hour).Truncate(24 * time.Hour)
 	visit, _ := db.GetDayVisits(start)
-	prevDay := start.Day()
-	i := 0
 	for _, v := range visit {
-		day := time.Unix(v.Date/1000, 0).Day()
-		for prevDay+1 < day {
-			prevDay++
-			visits[i].Label = strconv.Itoa(prevDay)
-			visits[i].Count = 0
-			i++
-		}
-		visits[i].Label = strconv.Itoa(day)
-		visits[i].Count = v.Count
-		prevDay = day
-		i++
+		var elem visitData
+		day := time.Unix(v.Date/1000, 0).UTC().Day()
+		elem.Label = strconv.Itoa(day)
+		elem.Count = v.Count
+		visits = append(visits, elem)
+	}
+
+	return visits
+}
+
+func getMonthlyVisits() []visitData {
+	const numDays = 365
+	var visits []visitData
+
+	start := time.Now().UTC().Add(-numDays * 24 * time.Hour).Truncate(24 * time.Hour)
+	visit, _ := db.GetMonthVisits(start)
+	for _, v := range visit {
+		var elem visitData
+		month := time.Unix(v.Date/1000, 0).UTC().Month()
+		elem.Label = month.String()
+		elem.Count = v.Count
+		visits = append(visits, elem)
 	}
 
 	return visits
diff --git a/templates/stats.html b/templates/stats.html
index dd81785..d6f8b0d 100644
--- a/templates/stats.html
+++ b/templates/stats.html
@@ -3,27 +3,39 @@
 <script src="/js/Chart.min.js"></script>
 
 <div class="row">
+	<h4>Hourly visits:</h4>
+	<canvas id="hourly" height="400" width="800"></canvas>
 	<h4>Daily visits:</h4>
 	<canvas id="daily" height="400" width="800"></canvas>
+	<h4>Monthly visits:</h4>
+	<canvas id="monthly" height="400" width="800"></canvas>
 </div>
 
 <script type="text/javascript">
-	var data = {
-		labels : [{{range .Daily}}"{{.Label}}",{{end}}],
-		datasets : [
-			{
-				fillColor : "rgba(151,187,205,0.5)",
-				strokeColor : "rgba(151,187,205,1)",
-				pointColor : "rgba(151,187,205,1)",
-				pointStrokeColor : "#fff",
-				data : [{{range .Daily}}{{.Count}},{{end}}]
-			}
-		]
+	function chart(id, labels, counts) {
+		var data = {
+			labels : labels,
+			datasets : [
+				{
+					fillColor : "rgba(151,187,205,0.5)",
+					strokeColor : "rgba(151,187,205,1)",
+					pointColor : "rgba(151,187,205,1)",
+					pointStrokeColor : "#fff",
+					data : counts
+				}
+			]
+		}
+
+		var ctx = $(id).get(0).getContext("2d");
+		new Chart(ctx).Line(data);
 	}
 
-
-	var ctx = $("#daily").get(0).getContext("2d");
-	new Chart(ctx).Line(data);
+	chart("#hourly", [{{range .Hourly}}"{{.Label}}",{{end}}],
+			 [{{range .Hourly}}{{.Count}},{{end}}])
+	chart("#daily", [{{range .Daily}}"{{.Label}}",{{end}}],
+			[{{range .Daily}}{{.Count}},{{end}}])
+	chart("#monthly", [{{range .Monthly}}"{{.Label}}",{{end}}],
+			  [{{range .Monthly}}{{.Count}},{{end}}])
 </script>
 
 {{template "footer.html"}}