miércoles, 4 de abril de 2012

Funcion para Calcular Horas entre 2 Fechas descartando Fines de Semana SQL Server

En SQL Server existe la funcion dateDiff que devuelve la cantidad de días, horas, semanas, etc. entre dos fechas. Para mas información pueden revisar la documentación de msdn. Esta función es muy útil para realizar cálculos especiales, como antigüedad de registros o el tiempo de vida de alguna persona.

Sin embargo, en casos más especiales, se requeriría calcular el tiempo entre 2 fechas, pero solamente contando los días laborales. Lamentablemente, dateDiff no cuenta con algún parámetro para esto, por lo que hay que aplicar un poco de lógica para conseguirlo.

Basándome en un enlace construí una función que devolviera la cantidad de horas transcurridas entre 2 fechas, descontando fines de semana. Tal vez no sea la mejor manera, o las más optimizada, pero cumple decentemente su objetivo.

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

ALTER FUNCTION diffHoursWithoutWeekend

(

@fInicio smalldatetime,

@fFin smalldatetime

)

RETURNS int

AS

BEGIN

declare @noHoras int

declare @cuentaLab int

declare @contador int

select @noHoras = dateDiff(hour, @fInicio, @fFin)

select @cuentaLab = 0

select @contador = 0

while(@contador < @noHoras)

begin

declare @diaSemana int

select @diaSemana = datePart(weekDay, dateAdd("hh", @contador, @fInicio))

if (@diaSemana <> 1 and @diaSemana <> 7)

begin

select @cuentaLab = @cuentaLab + 1

end

select @contador = @contador + 1

end

RETURN @cuentaLab

END

GO


Como pueden ver, la función recibe como parámetros de entrada 2 fechas para posteriormente calcular las horas entre ambas. Posteriormente utilizando un ciclo, por cada hora transcurrida determinamos si es fin de semana (por defecto en SQL Server, Domingo es 1, Lunes es 2, etc). En caso de que sea un día laboral, aumentamos el contador de las horas.

La función puede ser fácilmente transformada para que devuelva la cantidad de días. En el enlace indicado viene un ejemplo que lo puede mostrar, así como también una solución propuesta para los casos que se desee descartar días feriados.

Espero les sea útil y cualquier comentario o mejora es bienvenida.

domingo, 18 de marzo de 2012

Ejecutar PostBack de un control con C# y Javascript

Buscando información de como subir imágenes al servidor utilizando ASP.NET, me encontré con un artículo interesante, que muestra un ejemplo sobre el tema donde resalta como ejecutar el evento PostBack de un linkButton, utilizando el método __doPostBack en Javascript.

Lo que hace el siguiente código es utilizar un control fileUpload para subir una imagen. Lo que hace diferente es que no utiliza un botón extra para ejecutar el postback y enviar el archivo al servidor, si no que al momento de que el usuario lo selecciona, se ejecuta el evento de un linkButton oculto que tiene el código necesario para subir la imagen.

Esto se logra invocando el método __doPostBack, seleccionando el control que se desea ejecutar. De esta manera, desde javascript podemos invocar el code behind que necesitemos para lograr un objetivo.

Además, el ejemplo muestra como crear un thumbnail o vista previa de la imágen y se pregunta al usuario si desea guardarla o no. Ya esto último es extra y puede caer en discusión su funcionalidad.

Los controles principales que se necesitan son:
  • FileUpload de nombre fileUpload.
  • HiddenField de nombre hdFileName
  • HiddenField de nombre hdFileNameThumb
  • LinkButton de nombre linkBt
  • Button de nombre btGuardar
  • Button de nombre btCancelar
  • Image de nombre image
Además necesitamos los siguientes espacios de nombre:

using System.IO;
using System.Drawing.Imaging;

Y el código es el siguiente:

Las funciones Javascript:

var x = 5000;
var Guardar;
function asignarRutaImagen()
{
/*Esta funcion esperara hasta que el usuario haya elegido un archivo*/
var tiempo, tiempo2;
if(x >= 0)
{
x-=1;
if (document.form1.fileUpload.value == "")
{
tiempo2 = setTimeout("asignarRutaImagen()", 50);
}
else
{
document.form1.hdFileName.value =
document.form1.fileUpload.value;
x=-1;
/*Genera un postback e invoca el evento
click del linkbutton*/
__doPostBack('linkBt','');
}
}
}
function validarkey()
{
/*Para que use el browse y no teclee la ruta*/
alert ("Presione el boton Browse para buscar una imagen");
return false;
}

El CodeBehind:

protected void Page_Load(object sender, EventArgs e)
{
/*Hacemos limpieza del buffer y encabezados*/
this.Response.BufferOutput = false;
this.Response.Clear();
this.Response.ClearHeaders();
/*Agregamos al FileUpload, a sus eventos onclick y onkeypress,
las funciones asignarRutaFoto y validarKey*/
this.fileUpload.Attributes.Add("onclick",
"javascript:asignarRutaImagen();");
this.fileUpload.Attributes.Add("onkeypress",
"javascript:return validarkey();");
}

protected void linkBt_Click(object sender, EventArgs e)
{
try
{
/*Este evento se generara desde la funcion javascript
asignarRutaFoto*/
if (this.fileUpload.HasFile == true)
{
cargarFotografia();
mostrarImagen();
this.btGuardar.Visible = true;
this.btCancelar.Visible = true;
}
}
catch (Exception ex)
{
this.lblMsg.Text = ex.Message;
}
}

private void cargarFotografia()
{
/*Obtenemos el nombre y la extension del archivo*/
String fileName = Path.GetFileName(this.fileUpload.PostedFile.FileName);
String extension = Path.GetExtension(
this.fileUpload.PostedFile.FileName).ToLower();
try
{
if (extension != ".png" && extension != ".jpg" &&
extension != ".bmp")
{
this.lblMsg.Text = "El archivo ingresado no es una imagen";
}
else
{
/*Se guarda la imagen en el servidor*/
this.fileUpload.PostedFile.SaveAs(
Server.MapPath("\\imagesTemp\\") + fileName);
/*Obtenemos el nombre temporal de la imagen
con la siguiente funcion*/
String nombreImgServer = getNombreImagenServidor(extension);
this.hdFileName.Value = nombreImgServer;
/*Cambiamos el nombre de la imagen por el nuevo*/
File.Move(Server.MapPath("\\imagesTemp\\") + fileName,
Server.MapPath("\\imagesTemp\\" + nombreImgServer));
}
}
catch (Exception ex)
{
this.lblMsg.Text = ex.Message;
}
}

public String getNombreImagenServidor(String extension)
{
/*Devuelve el nombre temporal de la imagen*/
Random nRandom = new Random();
String nr = Convert.ToString(nRandom.Next(0, 32000));
String nombre = nr + "_" + DateTime.Today.ToString("ddMMyyyy") + extension;
nRandom = null;
return nombre;
}

private void mostrarImagen()
{
/*Muestra la imagen como un thumbnail*/
System.Drawing.Image objImage = null, objThumbnail = null;
Int32 width, height;
String fileName = Server.MapPath("imagesTemp\\") +
Path.GetFileName(this.hdFileName.Value);
Stream stream = null;
try
{
/*Se guarda la imagen en un stream para despues colocarla
en un objeto para que la imagen no quede abierta en el servidor*/
stream = File.OpenRead(fileName);
objImage = System.Drawing.Image.FromStream(stream);
width = 100;
height = objImage.Height / (objImage.Width / width);
this.Response.Clear();
/*Se crea el thumbnail y se muestra en la imagen*/
objThumbnail = objImage.GetThumbnailImage(
width, height, null, IntPtr.Zero);
objThumbnail.Save(Server.MapPath("imagesTemp\\") +
"thumb_" + this.hdFileName.Value, ImageFormat.Jpeg);
this.image.Visible = true;
String nombreImgThumb = "thumb_" + this.hdFileName.Value;
this.hdFileNameThumb.Value = nombreImgThumb;
this.image.ImageUrl = "~/imagesTemp//" + nombreImgThumb;
}
catch(Exception ex)
{
this.lblMsg.Text = ex.Message;
}
finally
{
/*Limpiamos los objetos*/
objImage.Dispose();
objThumbnail.Dispose();
stream.Dispose();
objImage = null;
objThumbnail = null;
stream = null;
}
}

protected void btGuardar_Click(object sender, EventArgs e)
{
try
{
/*Borramos la imagen thumbnail y movemos la imagen elegida a la
carpeta correcta*/
if (this.hdFileNameThumb.Value.Length > 0)
{
File.Delete(Server.MapPath("\\imagesTemp\\" +
this.hdFileNameThumb.Value));
}
if (this.hdFileName.Value.Length > 0)
{
File.Move(Server.MapPath("\\imagesTemp\\") +
this.hdFileName.Value, Server.MapPath("\\images\\" +
this.hdFileName.Value));
}
}
catch (Exception ex)
{
this.lblMsg.Text = ex.Message;
}
}

protected void btCancelar_Click(object sender, EventArgs e)
{
try
{
/*Borramos las imagenes de la carpeta temporal*/
if (this.hdFileNameThumb.Value.Length > 0)
{
File.Delete(Server.MapPath("\\imagesTemp\\" +
this.hdFileNameThumb.Value));
}
if (this.hdFileName.Value.Length > 0)
{
File.Delete(Server.MapPath("\\imagesTemp\\" +
his.hdFileName.Value));
}
}
catch (Exception ex)
{
this.lblMsg.Text = ex.Message;
}
}

Les dejo algunas imágenes de su funcionamiento y la liga al código fuente para que lo descarguen si desean mayor referencia.




Espero les sea útil y cualquier comentario o crítica es bien recibida.

jueves, 15 de marzo de 2012

Poder sin Límites... o el sueño de cualquier nerd


A pesar de que en México es casi nula su promoción, me tope en cartelera esta película y decidí ir a verla, recordando un trailer que vi hace un tiempo y un vídeo viral que salio en las noticias de gente volando en Nueva York. La película esta grabada en el formato de falso documental así que si les gusto Cloverfield o REC, esta definitivamente les agradará.

Sin ganas de hacer spoiler, imagínense a tres chavos que un día se encuentran una extraña roca, al puro estilo kriptonita, que les otorga unos extraños poderes para mover cosas con la mente, volar y una gran fuerza. El sueño de cualquier nerd adolescente..., por que a poco no imaginaron defenderse de lo brabucones o impresionar a las chicas con tales poderes, por que yo si, aunque bueno... esa es otra historia.

El chiste de la película no es solo las demostraciones de los chavos y sus habilidades, si no tal como es la campaña del filme, ¿de que serían capaces?... como diría Ben Parker "con un gran poder viene una gran responsabilidad". ¿Que harían si tuvieran una super fuerza, pudieran volar o movieran cosas con la mente?, ¿serían super heroes luchando por el bien y la justicia?... o ¿se dejarían llevar por el lado oscuro?.

Pues la película presenta una muy buena historia, al principio muy clásica ("ah, eso ya lo he visto") pero que avanza captando la atención con sus acciones, después con su comportamiento y al final con un enfrentamiento entre los mas profundos instintos de los protagonistas.

Y el estilo de falso documental le da un sentido más "protagónico" por que te hacen sentir uno de ellos, siendo parte de las bromas, volando por los aires o incluso haciendo a un lado las "molestias". También agrada mucho el hecho de que no es solo una cámara la que cuenta la historia, si no varias que se van presentando durante la película, y aunque al final ya no sabes cuál es cuál la que esta tomando a quien, no se pierde la sensación de ser un protagónico más.

Realmente me busco la película, son de esas de las que sales de la sala tratando de hacer lo que viste, imaginándote salir volando o preguntándote las cosas que harías si tuvieras esos poderes. Lo genial que sería ser malo, o lo bien que te sentirías haciendo el bien.

En fin, si no se marean fácilmente, es una buen película que disfrutarán; y aunque su duración es de casi 90 minutos, te deja con buen sabor de boca y preguntándote si habrá una 2da parte. Bueno, me adelanto contestándoles que al parecer sí, puesto que ha generado muchas ganancias alrededor del mundo por lo que la FOX ya esta preparando la secuela.