ISO 8601/RFC 3339 Compatible Dates
Posted: October 4, 2009 Filed under: .NET General, Code | Tags: Dates, Extension Methods, ISO, RFC Leave a comment »There are not standard format specifiers for date that takes a date and converts it to an ISO 8601 or RFC 3339 compatible date. Here are two extension methods that does just that.
public static string ToISO8601(this DateTime date)
{
return date.ToString("yyyy-MM-dd");
}
public static string ToRFC3339(this DateTime date)
{
return date.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ssZ");
}
Generating a Slug From a String
Posted: October 2, 2009 Filed under: .NET General, Code | Tags: Extension Methods, Slug, Unicode, url Leave a comment »I can’t (and won’t) take full credit for this extension method. The hardcore Unicode stuff is from Michael Kaplan’s blog (jeez, he is hardcore). There is a little danish “stuff” included, for special characters æ, ø and å, which can also be written “ae”, “oe” an “aa”.
public static string ToSlug(this string message)
{
// replace space with -
message = Regex.Replace(message, @"[\s/\\\.,+|_]+", "-");
// normalize the message
message = message.Normalize(NormalizationForm.FormD);
message = message.Replace("ø", "oe").Replace("Ø", "Oe").Replace("æ", "ae").Replace("Æ", "Ae").Replace("å", "aa").Replace("Å", "Aa");
StringBuilder result = new StringBuilder();
for (int i = 0; i < message.Length; i++)
{
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(message[i]);
if (uc != UnicodeCategory.NonSpacingMark)
{
result.Append(message[i]);
}
}
return Regex.Replace(result.ToString().Normalize(NormalizationForm.FormC), @"[^a-zA-Z0-9\-]", "").ToLower();
}
ASP.NET MVC Gravatar HtmlHelper
Posted: September 30, 2009 Filed under: ASP.NET MVC, Code | Tags: ASP.NET MVC, Extension Methods, Gravatar 1 Comment »Here is a quick little URL Helper extension method to add Gravatar images/photos/avatars to your page:
public static string GravatarUrl(this UrlHelper url, string email, int size)
{
string imageUrl = ConfigurationManager.AppSettings["DefaultGravatar"];
if (imageUrl.StartsWith("~/"))
{
imageUrl = url.Absolute(imageUrl);
}
if (string.IsNullOrEmpty(email))
{
return imageUrl;
}
string md5 = email.ToLowerInvariant().MD5();
return string.Format(
"http://www.gravatar.com/avatar/{0}.jpg?d={1}&s={2}&r=g",
md5.ToLowerInvariant(),
url.Encode(imageUrl),
size);
}
public static string GravatarUrl(this UrlHelper url, string email)
{
return url.GravatarUrl(email, 32);
}
It uses another custom URL Helper extension method Absolute to generate an absolute URL to a default image (based on an application relative url).
The Absolute extension method is similar to the ActionAbsolute method I posted earlier:
public static string Absolute(this UrlHelper url, string contentUrl)
{
return new Uri(GetBaseUrl(url), url.Content(contentUrl))
.AbsoluteUri;
}
And it also used the MD5 extension method from yesterdays post.
MD5 Extension Method
Posted: September 29, 2009 Filed under: .NET General, Code | Tags: Extension Methods, hash, md5, Secure Hash 1 Comment »A nifty little extension method that generated the MD5/SHA-1 hash of a string. These methods are a continuation of my previous post:
public static string MD5(this string value)
{
System.Security.Cryptography.MD5 algorithm =
System.Security.Cryptography.MD5.Create();
byte[] data = Encoding.ASCII.GetBytes(value);
data = algorithm.ComputeHash(data);
string md5 = "";
for (int i = 0; i < data.Length; i++)
{
md5 += data[i].ToString("x2").ToLower();
}
return md5;
}
Just substitute MD5 for SHA1, SHA256, SHA384, SHA512 or RIPEMD160 which ever hash algorithm fits your needs.
Relative Time Description
Posted: September 28, 2009 Filed under: .NET General, Code | Tags: Dates, Extension Methods Leave a comment »Showing an absolute date on a webpage, e.g. January 22, 2009 13:01, is of course a very normal way to do it, apart from various different date formats, it is easily read and consumed. However if the date is shown in a context where the absolute date is of little importance, but it is more important to know if it was a long time ago, just now or maybe just in a couple of minutes, a relative and more descriptive method is better.
For example the date mentioned above might be described as “8 months ago”. Just by giving it a quick glance you get an idea about when this event occurred.
For this here are a couple of extension methods that generate this descriptive text based on a given time:
public static string ToRelativeTime(this DateTime from)
{
DateTime now = DateTime.Now;
return from.ToRelativeTime(now);
}
public static string ToRelativeTime(this DateTime from, bool usePreAndSuffix)
{
DateTime now = DateTime.Now;
return from.ToRelativeTime(now, usePreAndSuffix);
}
public static string ToRelativeTime(this DateTime from, DateTime to)
{
return from.ToRelativeTime(to, true);
}
public static string ToRelativeTime(this DateTime from, DateTime to, bool usePreAndSuffix)
{
string prefix = usePreAndSuffix && (from > to) ? "in " : string.Empty;
string suffix = !usePreAndSuffix || (from > to) ? string.Empty : " ago";
// is more than 1 year?
if (from > to)
{
DateTime d = from;
from = to;
to = d;
}
int years = to.Year - from.Year;
if ((to.Month < from.Month) || ((to.Month == from.Month) && (to.Day < from.Day)))
{
years--;
}
if (years > 1)
{
return string.Format("{0}{1} years{2}", prefix, years, suffix);
}
else if (years == 1)
{
return string.Format("{0}1 year{1}", prefix, suffix);
}
// less than 1 year, is more than 1 month?
int months = to.Month - from.Month;
if (months < 0)
{
months += 12;
}
if ((to.Day < from.Day) || ((to.Day == from.Day) && (to.TimeOfDay < from.TimeOfDay)))
{
months--;
}
if (months > 1)
{
return string.Format("{0}{1} months{2}", prefix, months, suffix);
}
else if (months == 1)
{
return string.Format("{0}1 month{1}", prefix, suffix);
}
// less than 1 month, is more than 1 day/week?
TimeSpan diff = to - from;
if (diff.Days > 7)
{
return string.Format("{0}{1} weeks{2}", prefix, diff.Days / 7, suffix);
}
else if (diff.Days > 1)
{
return string.Format("{0}{1} days{2}", prefix, diff.Days, suffix);
}
else if (diff.Days == 1)
{
return string.Format("{0}1 day{1}", prefix, suffix);
}
// less than 1 day, is more than 1 hour?
if (diff.Hours > 1)
{
return string.Format("{0}{1} hours{2}", prefix, diff.Hours, suffix);
}
else if (diff.Hours == 1)
{
return string.Format("{0}1 hour{1}", prefix, suffix);
}
// less than 1 hour, is more than 1 minute?
if (diff.Minutes > 1)
{
return string.Format("{0}{1} minutes{2}", prefix, diff.Minutes, suffix);
}
else if (diff.Minutes == 1)
{
return string.Format("{0}1 minute{1}", prefix, suffix);
}
// less than 1 minute
if (diff.Seconds == 1)
{
return string.Format("{0}1 second{1}", prefix, suffix);
}
else if (diff.Seconds < 1)
{
return string.Format("{0}less than 1 second{1}", prefix, suffix);
}
return string.Format("{0}{1} seconds{2}", prefix, diff.Seconds, suffix);
}
This can of course be optimized for localization etc.